【发布时间】:2011-05-28 05:59:53
【问题描述】:
在 JUnit 中,我目前正在使用注解来预期我的测试中会出现异常。
有没有办法分析这个异常?比如我期待一个CriticalServerException,但我也想验证getMessage方法的内容。
【问题讨论】:
在 JUnit 中,我目前正在使用注解来预期我的测试中会出现异常。
有没有办法分析这个异常?比如我期待一个CriticalServerException,但我也想验证getMessage方法的内容。
【问题讨论】:
如果您有 JUnit 4.7 或更高版本,请尝试ExpectedException
this question中有一个例子,复制如下:
@Rule
public ExpectedException exception = ExpectedException.none();
@Test
public void testRodneCisloRok(){
exception.expect(IllegalArgumentException.class);
exception.expectMessage("error1");
new RodneCislo("891415",dopocitej("891415"));
}
【讨论】:
exception对象中设置后调用方法对我来说是关键。
我不确定你是否应该这样做。使用 try-catch 块来检查错误消息是如此 junit3ish。我们现在有了这个很酷的功能,您可以写 @Test(expected=CriticalServerException.class) 并且您想“返回”并再次使用 try-catch 来获取您期望的异常,只是为了检查错误消息?
IMO 你应该留下@Test(expected=CriticalServerException.class) 注释并忽略错误消息。检查错误消息,因为它是一个更“人类可读”的字符串而不是技术值,所以可以更改很多,也可能很棘手。您正在强制异常具有特定的错误消息,但您可能不知道谁生成了异常以及他选择了什么错误消息。
一般来说,您想测试方法是否抛出异常,而不是实际错误消息的样子。如果错误消息真的很重要,您可能应该考虑使用它抛出的异常的子类并在@Test(expected=...) 中检查它。
【讨论】:
try{
//your code expecting to throw an exception
fail("Failed to assert :No exception thrown");
} catch(CriticalServerException ex){
assertNotNull("Failed to assert", ex.getMessage())
assertEquals("Failed to assert", "Expected Message", ex.getMessage());
}
【讨论】:
try
{
// your code
fail("Didn't throw expected exception");
}
catch(CriticalServerException e)
{
assertEquals("Expected message", e.getMessage());
}
【讨论】:
try {
// test code invacation
fail("Exception not throw!!!");
} catch(CriticalServerException ex) {
assertTrue("Invalid exception data", ex.toString().contains("error text"));
}
【讨论】:
如果您有很多测试用例要测试,请使用 MethodRule 作为常用解决方案
public class ExceptionRule implements MethodRule {
@Override
public Statement apply(final Statement base, final FrameworkMethod method, Object target) {
return new Statement() {
@Override
public void evaluate() throws Throwable {
try {
base.evaluate();
Assert.fail();
} catch (CriticalServerException e) {
//Analyze the exception here
}
}
};
}
}
然后在你的测试类中使用规则:
@Rule public ExceptionRule rule = new ExceptionRule();
【讨论】:
我认为没有办法使用注释来做到这一点。您可能不得不退回到 try-catch 方式,在 catch 块中您可以验证消息
【讨论】:
catchException(obj).doSomethingCritical();
assertTrue(caughtException() instanceof CriticalServerException);
assertEquals("Expected Message", caughtException().getMessage());
【讨论】:
看看fluent-exception-rule,它“结合了 Junit ExpectedException 规则和 AssertJ 的断言便利性。”
import pl.wkr.fluentrule.api.FluentExpectedException;
...
@Rule
public FluentExpectedException thrown = FluentExpectedException.none();
@Test
public void testDoSomethingCritical() {
thrown.expect(CriticalServerException.class).hasMessage("Expected Message").hasNoCause();
obj.doSomethingCritical();
}
【讨论】:
如果你想比较消息和异常类型,那么你可以试试下面的代码 sn-p。
@Rule
public ExpectedException expectedException = ExpectedException.none();
expectedException.expect(IllegalArgumentException.class);
expectedException.expectMessage("Parameter is not valid"); //check string contains
expectedException.expectMessage(CoreMatchers.equalTo("Parameter is not valid")); //check string equals
注意:这将适用于 junit 4.9 以后的版本。
【讨论】:
这是我写的一个实用函数:
public final <T extends Throwable> T expectException( Class<T> exceptionClass, Runnable runnable )
{
try
{
runnable.run();
}
catch( Throwable throwable )
{
if( throwable instanceof AssertionError && throwable.getCause() != null )
throwable = throwable.getCause(); //allows "assert x != null : new IllegalArgumentException();"
assert exceptionClass.isInstance( throwable ) : throwable; //exception of the wrong kind was thrown.
assert throwable.getClass() == exceptionClass : throwable; //exception thrown was a subclass, but not the exact class, expected.
@SuppressWarnings( "unchecked" )
T result = (T)throwable;
return result;
}
assert false; //expected exception was not thrown.
return null; //to keep the compiler happy.
}
如下使用:
@Test
public void testThrows()
{
RuntimeException e = expectException( RuntimeException.class, () ->
{
throw new RuntimeException( "fail!" );
} );
assert e.getMessage().equals( "fail!" );
}
另外,如果您想了解您应该不检查异常消息的一些原因,请参阅:https://softwareengineering.stackexchange.com/a/278958/41811
【讨论】: