ChatGPT解决这个技术问题 Extra ChatGPT

有条件地忽略 JUnit 4 中的测试

好的,所以 @Ignore 注释非常适合标记不应运行测试用例。

但是,有时我想忽略基于运行时信息的测试。例如,如果我有一个并发测试需要在具有一定数量内核的机器上运行。如果这个测试是在单处理器机器上运行的,我认为只通过测试是不正确的(因为它还没有运行),而且测试失败并破坏构建肯定是不对的.

所以我希望能够在运行时忽略测试,因为这似乎是正确的结果(因为测试框架将允许构建通过但记录测试未运行)。我相当确定注释不会给我这种灵活性,并且怀疑我需要为相关类手动创建测试套件。但是,文档没有提及任何关于此的内容,并且通过 API 查看它也不清楚这将如何以编程方式完成(即,我如何以编程方式创建 Test 的实例或类似于由@Ignore 注释?)。

如果有人过去做过类似的事情,或者对我还能如何解决这个问题有一个好主意,我会很高兴听到这个消息。


t
tkruse

JUnit 在运行时执行此操作的方法是 org.junit.Assume

 @Before
 public void beforeMethod() {
     org.junit.Assume.assumeTrue(someCondition());
     // rest of setup.
 }

您可以在 @Before 方法或测试本身中执行此操作,但不能在 @After 方法中执行。如果您在测试本身中执行此操作,您的 @Before 方法将运行。您也可以在 @BeforeClass 内执行此操作以防止类初始化。

假设失败会导致测试被忽略。

编辑: 为了与 junit-ext 中的 @RunIf 注释进行比较,他们的示例代码如下所示:

@Test
public void calculateTotalSalary() {
    assumeThat(Database.connect(), is(notNull()));
    //test code below.
}

更不用说以这种方式从 Database.connect() 方法捕获和使用连接要容易得多。


@notnoop,这根本不是我的观察。他们被忽略了。 IDEA 测试运行程序以这种方式报告它们,并且查看 JUnit 源代码显示它报告测试为忽略。
引用:“将来,这可能会改变,失败的假设可能会导致测试被忽略。”它实际上改变了,我相信从 4.5 开始。当前的 javadoc 说:“默认的 JUnit 运行程序将具有失败假设的测试视为忽略。自定义运行程序的行为可能不同。” github.com/KentBeck/junit/blob/…
带有 Junit 4.8.1 的 Eclipse 3.6 将错误假设报告为通过测试。与蚂蚁 1.8.1 相同。
Eclipse 将失败的假设报告为通过是一个错误:bugs.eclipse.org/bugs/show_bug.cgi?id=359944
@JeffStorey,那么您正在寻找一些东西。一个是 @BeforeClass 注释,您可以在那里让您的假设失败,这将跳过整个课程。另一个是 @ClassRule(用于细粒度控制,但在整个班级,一次)。
R
Ryan Li

您应该签出 Junit-ext 项目。它们具有执行条件测试的 RunIf 注释,例如:

@Test
@RunIf(DatabaseIsConnected.class)
public void calculateTotalSalary() {
    //your code there
}

class DatabaseIsConnected implements Checker {
   public boolean satisify() {
        return Database.connect() != null;
   }
}

[取自他们的教程的代码示例]


感谢您的回答 - 该功能的一种有趣的替代语法,尽管我将直接使用 Assume 以避免引入另一个依赖项。
我个人更喜欢这个解决方案。如果您有许多测试应该基于相同的条件运行,这将比在每个测试中都使用 Assume 更理想。此外,如果这可以在类级别而不是方法级别上使用,那将更加理想。
我更喜欢它,因为这有助于在运行时有条件地运行测试。它适合要运行许多单元测试的地方,并且要求是在特定检查器上运行单元测试。看到 junit-ext 在 maven 存储库上不可用,我真的很惊讶。我们如何在 Maven 项目中利用这一点。
@RunIf 这样的注释将测试应该运行的条件与实际测试代码分开,我认为这很好。我不喜欢的是它需要一个特定的测试运行器。因此我写了一个 JUnit rule 来条件性地忽略测试。
在我们的本地存储库中安装 junit-ext jar(在此处找到 code.google.com/p/junit-ext/downloads/… )并实现此 @RunIf 注释后......什么都没有!它完全被忽略了,我认为原因可能是 junit-ext 似乎依赖于 junit 4.5。由于弹簧测试,我们需要 4.9+。所以……别介意。
K
Kyle Shrader

在 JUnit 4 中,您的另一个选择可能是创建一个注释以表示测试需要满足您的自定义标准,然后使用您自己的和使用反射扩展默认运行程序,根据您的自定义标准做出决定。它可能看起来像这样:

public class CustomRunner extends BlockJUnit4ClassRunner {
    public CTRunner(Class<?> klass) throws initializationError {
        super(klass);
    }

    @Override
    protected boolean isIgnored(FrameworkMethod child) {
        if(shouldIgnore()) {
            return true;
        }
        return super.isIgnored(child);
    }

    private boolean shouldIgnore(class) {
        /* some custom criteria */
    }
}

虽然这看起来很干净,但它不适用于 JUnit4 的当前版本,因为 BlockJUnit4ClassRunner 不再提供 isIgnored 方法。
J
Juergen

除了@tkruse 和@Yishai 的回答之外
我这样做是为了有条件地跳过测试方法,尤其是对于Parameterized 测试,如果测试方法应该只针对某些测试数据记录运行。

public class MyTest {
    // get current test method
    @Rule public TestName testName = new TestName();
    
    @Before
    public void setUp() {
        org.junit.Assume.assumeTrue(new Function<String, Boolean>() {
          @Override
          public Boolean apply(String testMethod) {
            if (testMethod.startsWith("testMyMethod")) {
              return <some condition>;
            }
            return true;
          }
        }.apply(testName.getMethodName()));
        
        ... continue setup ...
    }
}

S
Serg

快速说明:Assume.assumeTrue(condition) 忽略其余步骤但通过了测试。要使测试失败,请在条件语句中使用 org.junit.Assert.fail()。与 Assume.assumeTrue() 一样工作,但未通过测试。


如上面的答案所述,失败的假设不会导致测试通过,它会返回一个单独的状态。一些运行程序可能会错误地将其报告为通过,但这是测试运行程序中的一个弱点/错误(并且默认的 JUnit 运行程序将测试显示为已忽略)。至于你的最后一句话,考试不及格并不是我想要做的。
哦好的。在我的情况下,测试通过了失败的假设,但我希望它们被报告为失败(我正在检查来自测试观察器的异常)。强迫失败帮助了我。