Java jUnit忽略基类中的@Test方法

Java jUnit忽略基类中的@Test方法,java,inheritance,junit,Java,Inheritance,Junit,假设我有一个名为testFixtureA的测试类,它有几个方法testA,testB,testC,等等,每个方法都带有@test注释 现在让我们假设我将testFixtureA子类化到名为testFixtureAB的类中,并且我不覆盖任何内容testFixtureAB目前为空 当我从testFixtureAB运行测试时,方法testA、testB和testC由测试运行程序执行,因为测试运行程序不区分类和基类的测试方法 如何强制测试运行程序忽略基类中的测试?忽略整个基类: @Ignore clas

假设我有一个名为
testFixtureA
的测试类,它有几个方法
testA
testB
testC
,等等,每个方法都带有
@test
注释

现在让我们假设我将
testFixtureA
子类化到名为
testFixtureAB
的类中,并且我不覆盖任何内容
testFixtureAB
目前为空

当我从
testFixtureAB
运行测试时,方法
testA
testB
testC
由测试运行程序执行,因为测试运行程序不区分类和基类的测试方法


如何强制测试运行程序忽略基类中的测试?

忽略整个基类:

@Ignore
class BaseClass {
   // ...
}

重新构造测试类

  • 如果您不想使用基类中的测试,那么不要扩展它
  • 如果您需要基类中的其他功能,请将该类分成两部分-测试和其他功能

在最新的JUnit中,您可以在子类上使用@Rule注释来检查测试名称并截取测试运行以动态忽略测试。但是我认为@Bozho的想法是更好的——你需要这样做的事实表明了一个更大的问题,这可能表明继承在这里不是正确的解决方案

我不会覆盖任何内容。 testFixtureAB目前为空

这是你的答案。如果不想从主类运行testB,请跳过它:

public class testFixtureAB extends testFixtureA {
   @Override
   public void testB() {}
}

我知道,这不是答案

考虑一下扩展具体测试类的原因。这样就可以复制测试方法

如果您在测试之间共享代码,那么考虑用OR或.


如果要运行测试,请尝试使用套件和组织测试。

如果要对同一测试套件的不同配置执行同一测试,该怎么办

例如,假设您有一个包含test1、test2和test3方法的类,这些方法命中一个嵌入式数据库,然后您希望为每个嵌入式供应商(H2、HyperSQL等)创建单独的“设置”和“拆卸”,但对每个供应商都运行相同的测试


我想扩展一个包含这些测试方法的类,并在子类中配置它。我的问题是,超级类不应该被认为有资格成为测试运行者。当测试运行程序执行超类时,如果没有找到相应的设置和拆卸方法,就会出现问题:(

实现一些类很容易:

  • 创建自己的
    TestRunner
  • 创建类似于
    @IgnoreInheritedTests
  • 创建一个扩展
    org.junit.runner.manipulation.Filter
在筛选器类上:

public class InheritedTestsFilter extends Filter {

    @Override
    public boolean shouldRun(Description description) {
        Class<?> clazz = description.getTestClass();
        String methodName = description.getMethodName();
        if (clazz.isAnnotationPresent(IgnoreInheritedTests.class)) {
            try {
                return clazz.getDeclaredMethod(methodName) != null;
            } catch (Exception e) {
                return false;
            }
        }
        return true;
    }

    @Override
    public String describe() {
        // TODO Auto-generated method stub
        return null;
    }

}
公共类继承的测试过滤器扩展了过滤器{
@凌驾
公共布尔值应运行(说明){
Class clazz=description.getTestClass();
String methodName=description.getMethodName();
if(clazz.isAnnotationPresent(IgnoreInheritedTests.class)){
试一试{
return clazz.getDeclaredMethod(methodName)!=null;
}捕获(例外e){
返回false;
}
}
返回true;
}
@凌驾
公共字符串descripe(){
//TODO自动生成的方法存根
返回null;
}
}
在自定义跑步器上:

 /**
 * @param klass
 * @throws InitializationError
 * @since
 */
public CustomBaseRunner(Class<?> klass) throws InitializationError {
    super(klass);
    try {
        this.filter(new InheritedTestsFilter());
    } catch (NoTestsRemainException e) {
        throw new IllegalStateException("class should contain at least one runnable test", e);
    }
}
/**
*@param-klass
*@throws初始化错误
*@自
*/
公共CustomBaseRunner(类klass)引发初始化错误{
超级(klass);;
试一试{
this.filter(新继承的testsfilter());
}捕获(notestsremaine异常){
抛出新的IllegalStateException(“类应至少包含一个可运行的测试”,e);
}
}

在基本测试类“@测试方法:

assumeTrue(getClass().equals(BaseClassTest.class));

它将忽略子类测试中的那些,但不会完全忽略它们。

如果出于任何原因,您需要两个JUnit类来实现相同的功能,对我来说最好的方法是:

  • 将公共代码放在父类
    TestFixture
    中,只包含常量和模拟服务
  • 创建两个子类:
    TestFixtureA
    TestFixtureB

这样,您就不会有重复的代码,也不会重复运行。

在JUnit5中,您可以将基类作为抽象类,并使用具体类对其进行扩展


当您在IDE中运行抽象时,您的子类将被执行。

这将忽略所有基类,使其基本上无用。使基类抽象?为了向其他人澄清,因为我第一次看到这个答案时不理解它,假设您在基类中有方法
testB
,并用@Test注释,你不希望
testB
test在你的子类中运行,然后转到子类,重写这个
testB
方法,那么这个测试将不再在你的子类中运行这是没有帮助的,因为@martosler在下面的答案中指出了这一点-有明显的情况(在我的情况下,针对不同浏览器的Selenium测试)这是一个非常糟糕的建议。有时你需要相同的行为;只是子类之间“SUT”变量的设置不同。@MikeBurton-事实上,这是一个很好的建议,尽管Bozho的建议可能并不明显。你需要做的是重构基类,提取应该重用到新类中的代码,(摘要)proto基类。然后,您的新测试类将扩展proto基类,而不是我们所称的基类。这将是一个遵循LSP和一般规则的好例子,即您永远不应覆盖具体实现。如果您不介意违反这些规则,您可以按照我下面的建议进行操作。我不采取行动我知道为什么我在七月份就反对这个,这正是我想要的解决方案