将单元测试标记为JUnit中的预期故障

Kal*_*son 40 java junit unit-testing

如何将测试标记为JUnit 4中的预期故障?

在这种情况下,我想继续运行此测试,直到上游修补了一些内容.忽略测试有点太过分了,因为那时我可能会忘记它.我可能能够添加一个@expected注释并捕获抛出的异常assertThat,但这似乎也与预期的行为有关.

这是我目前的测试结果:

@Test
public void unmarshalledDocumentHasExpectedValue() 
{
    doc = unmarshaller.unmarshal(getResourceAsStream("mydoc.xml"));
    final ST title = doc.getTitle();
    assertThat(doc.getTitle().toStringContent(), equalTo("Expected"));
}
Run Code Online (Sandbox Code Playgroud)

该断言应该成功,但由于上游错误,它不会.然而,那个测试是正确的; 它应该成功.事实上,我发现的所有替代方案都具有误导性.现在我认为这@Ignore("This test should pass once fixed upstream")是我最好的选择,但我仍然要记得回到它.我更喜欢测试运行.

在Python中我可以使用expectedFailure装饰器:

class ExpectedFailureTestCase(unittest.TestCase):
    @unittest.expectedFailure
    def test_fail(self):
        self.assertEqual(1, 0, "broken")
Run Code Online (Sandbox Code Playgroud)

使用Ct中的Qt QTestLib,您可以使用QEXPECT_FAIL:

QEXPECT_FAIL("", "Will be fixed next version", Continue);
QCOMPARE(i, 42);
Run Code Online (Sandbox Code Playgroud)

在上面的两种情况下,单元测试运行,这是我希望发生的.我在JUnit中遗漏了什么吗?

Bra*_*ace 25

我不太了解你的场景的细节,但这是我通常测试预期的失败:

光滑的新方式:

@Test(expected=NullPointerException.class)
public void expectedFailure() {
    Object o = null;
    o.toString();
}
Run Code Online (Sandbox Code Playgroud)

对于旧版本的JUnit:

public void testExpectedFailure() {
    try {
        Object o = null;
        o.toString();
        fail("shouldn't get here");
    }
    catch (NullPointerException e) {
        // expected
    }
}
Run Code Online (Sandbox Code Playgroud)

如果你想要确保抛出异常,你可能还想在循环中使用第二种技术,而不是为每种情况创建一个单独的测试方法.如果你只是在一个方法中使用循环遍历一堆案例expected,那么第一个抛出异常就会结束测试,并且不会检查后续的情况.

  • 这更好地处理:`@Test(expected = NullPointerException.class)`.然后你可以删除try/catch块和fail语句,因为JUnit会告诉你它预期有异常,如果没有抛出则没有收到异常. (2认同)

Mat*_*ell 17

我在这里假设您希望测试通过,如果您的断言失败,但如果断言成功,那么测试也应该通过.

最简单的方法是使用TestRule.TestRule提供了在运行测试方法之前和之后执行代码的机会.这是一个例子:

public class ExpectedFailureTest {
    public class ExpectedFailure implements TestRule {
        public Statement apply(Statement base, Description description) {
            return statement(base, description);
        }

        private Statement statement(final Statement base, final Description description) {
            return new Statement() {
                @Override
                public void evaluate() throws Throwable {
                    try {
                        base.evaluate();
                    } catch (Throwable e) {
                        if (description.getAnnotation(Deprecated.class) != null) {
                            // you can do whatever you like here.
                            System.err.println("test failed, but that's ok:");
                        } else {
                            throw e;
                        }
                    }
                }
            };
        }
    }

    @Rule public ExpectedFailure expectedFailure = new ExpectedFailure();

    // actually fails, but we catch the exception and make the test pass.
    @Deprecated
    @Test public void testExpectedFailure() {
        Object o = null;
        o.equals("foo");
    }

    // fails
    @Test public void testExpectedFailure2() {
        Object o = null;
        o.equals("foo");
    }
}
Run Code Online (Sandbox Code Playgroud)

首先,请注意第一种方法标记为@Deprecated.我正在使用它作为我想忽略任何断言失败的方法的标记.您可以做任何您喜欢的方法来识别方法,这只是一个例子.

接下来,ExpectedFailure#apply()当我执行base.evaluate()时,我正在捕获任何Throwable(包括AssertionError),如果方法用注释@Deprecated标记,我会忽略错误.您可以根据版本号,某些文本等执行您喜欢的任何逻辑来决定是否应该忽略错误.您还可以将动态确定的标志传递给ExpectedFailure,以允许它对某些版本号失败:

public void unmarshalledDocumentHasExpectedValue() {
    doc = unmarshaller.unmarshal(getResourceAsStream("mydoc.xml"));

    expectedFailure.setExpectedFailure(doc.getVersionNumber() < 3000);

    final ST title = doc.getTitle();
    assertThat(doc.getTitle().toStringContent(), equalTo("Expected"));
}
Run Code Online (Sandbox Code Playgroud)

有关更多示例,请参阅ExternalResourceExpectedException

忽略预期的故障测试而不是传递它

如果要将测试标记为忽略而不是成功,则会变得有点复杂,因为测试在执行之前会被忽略,因此您必须回顾性地将测试标记为忽略,这将涉及构建您自己的Runner.为了给你一个开始,请参阅我如何在套件中定义JUnit方法规则的答案.或者问另一个问题.


pho*_*ser 15

那么明确地期待一个AssertionError呢?

@Test(expected = AssertionError.class)
public void unmarshalledDocumentHasExpectedValue() {
    // ...
}
Run Code Online (Sandbox Code Playgroud)

如果您有理由相信测试中只有JUnit机器会引发AssertionError,那么这似乎就像任何事情一样自我记录.

你仍然冒着忘记这样一个测试的风险.如果有的话,我不会长时间让这些测试进入版本控制.


Aar*_*ver 7

一个选项是将测试标记为@Ignore并将文本放在那里,这可能是一个错误并等待修复.这样它就不会运行了.然后它会被跳过.您还可以以可能不同的方式使用扩展来满足您的需求.