在测试抛出异常的方法时验证行为

Verifying behavior when testing a method that throws an exception

最近,在代码审查中,一位同事说"Tests should not have try-catch blocks"。他还向我指出了有关 ExpectedException 的信息,我能够使用它来重写我的一些正在对异常数据执行检查的测试。

但是,我遇到了一种情况,我不确定是否可以消除 try-catch。我正在为将抛出异常 and 的方法编写单元测试,该异常将执行一些我需要使用 JMockit 验证的行为。假设被测代码包含类似

的内容
try {
    ...code...
} catch (SomeException e) {
    statusMessage.send("Failure", <parameters with some data>);
    throw e;
}

JUnit 测试目前看起来像

@Test
public void test() {
    ... set things up ...
    try {
        callTheMethod();
        fail("No exception thrown");
    } catch (Exception e) {
        assertEquals(SomeException.class, e.getClass());
    }
    new Verifications() { {
        statusMessage.send("Failure", <expected data>);
    } }
}

我找不到摆脱 try-catch 的好方法。我个人认为将它放在那里没有问题,但如果我不至少 尝试 摆脱它,我可能会 赶上 我的同事见鬼了 :) :) :)

failassertEquals 不是必需的。如果有一种简单的方法可以告诉 JUnit/JMockit 忽略来自 callTheMethod() 的任何异常并继续,那很好——我可以创建另一个测试来检查异常。

是否有一些 JUnit 或 JMockit 功能可以让我完成我想做的事情?

[注意:经过编辑以明确我正在测试的行为是对模拟对象的调用,而不是静态方法调用。它确实与问题无关。]

基于 API,我想你可以这样做:

class AjbUnitTest
{
    @Rule 
    public ExpectedException thrown = ExpectedException.none();

    @Test
    public void test()
    {
        ... set things up ...
        thrown.expect(SomeException.class)
        callTheMethod();  / Preumably this throws SomeException
        ...
    }
}

对于特定于异常的断言 AssertJ 有一个很好的 API:

@Test
public void testException() {
   assertThatThrownBy(() -> { throw new Exception("error!") })
     .isInstanceOf(Exception.class)
     .hasMessageContaining("error");
}

基本上,您可以 "collect" 异常而不中断测试执行。

您的同事在一般意义上可能是正确的,使用 try-catch 来测试您的异常处理不如使用提供的 ExpectedException 实用程序可取。但是,我认为该规则不适用于您的情况;捕获异常,以便您可以验证其他事情是否完全合理。没有其他方法可以阻止异常传播,AFAIK。

目前,如果您想在抛出断言后验证某些内容,则必须使用普通 JUnit try-catch。使用 JUnit 4.13(尚未发布)您可以使用

expectThrows(Exception.class, () -> callTheMethod());
new Verifications() { {
    statusMessage.send("Failure", <expected data>);
} }

作为替代方法,您可以使用 Fishbowl's ignoreException.

ignoreException(() -> callTheMethod());
new Verifications() { {
    statusMessage.send("Failure", <expected data>);
} }

完全披露:我是 Fishbowl 的作者。