如何在Java中使用Hamcrest测试异常?
如何使用Hamcrest测试异常?根据中的一条评论,“异常处理由JUnit4使用预期属性提供。” 所以我尝试了一下,发现它很有效:如何在Java中使用Hamcrest测试异常?,java,junit,hamcrest,Java,Junit,Hamcrest,如何使用Hamcrest测试异常?根据中的一条评论,“异常处理由JUnit4使用预期属性提供。” 所以我尝试了一下,发现它很有效: public class MyObjectifyUtilTest { @Test public void shouldFindFieldByName() throws MyObjectifyNoSuchFieldException { String fieldName = "status"; String field
public class MyObjectifyUtilTest {
@Test
public void shouldFindFieldByName() throws MyObjectifyNoSuchFieldException {
String fieldName = "status";
String field = MyObjectifyUtil.getField(DownloadTask.class, fieldName);
assertThat(field, equalTo(fieldName));
}
@Test(expected=MyObjectifyNoSuchFieldException.class)
public void shouldThrowExceptionBecauseFieldDoesNotExist() throws MyObjectifyNoSuchFieldException {
String fieldName = "someMissingField";
String field = MyObjectifyUtil.getField(DownloadTask.class, fieldName);
assertThat(field, equalTo(fieldName));
}
}
除了JUnit的@Test(预期=…)
注释之外,Hamcrest是否还提供了其他功能
当有人在Groovy()中询问这个问题时,我的问题是关于用Java编写的单元测试。您真的需要使用
Hamcrest
库吗
如果没有,下面是如何使用Junit对异常测试的支持来实现的。这个类有很多方法,除了检查抛出的异常的类型之外,您还可以使用它们来做您想做的事情
您可以结合使用Hamcrest
匹配器来断言特定的内容,但最好让Junit
预期抛出的异常
public class MyObjectifyUtilTest {
// create a rule for an exception grabber that you can use across
// the methods in this test class
@Rule
public ExpectedException exceptionGrabber = ExpectedException.none();
@Test
public void shouldThrowExceptionBecauseFieldDoesNotExist() throws MyObjectifyNoSuchFieldException {
String fieldName = "someMissingField";
// a method capable of throwing MyObjectifyNoSuchFieldException too
doSomething();
// assuming the MyObjectifyUtil.getField would throw the exception,
// I'm expecting an exception to be thrown just before that method call
exceptionGrabber.expect(MyObjectifyNoSuchFieldException.class);
MyObjectifyUtil.getField(DownloadTask.class, fieldName);
...
}
}
这种方法比
@Test(预期=…)
方法,因为只有@Test(预期=…)
通过抛出给定的异常来测试方法执行是否停止,
如果您想要抛出异常的调用抛出异常,则不会。例如,即使doSomething
方法抛出了可能不需要的MyObjectifyNoSuchFieldException
异常,测试也会成功
- 您需要测试的不仅仅是抛出的异常的类型。例如,您可以检查特定的异常实例或异常消息等
- 由于可读性和简洁性,
try/catch
block方法
如果计算断言错误描述,我无法很好地实现它(可能这就是为什么Hamcrest没有提供这样一个功能),但是如果您使用Java 8玩得很好,那么您可能会想要这样的东西(但是我认为它永远不会被使用,因为下面描述的问题):
它是可运行的
此接口用于包装可能引发异常的代码<代码>可调用
也可以使用,但后者需要返回一个值,因此我认为runnable(“void Callable”)更方便
@functioninterface
公共接口IThrowingRunnable{
无效运行()
抛出E;
}
故障匹配器
此类实现了一个匹配器,该匹配器要求给定的回调引发异常。此实现的一个缺点是,回调引发意外异常(甚至不引发单一异常)并不能描述错误,并且您会看到完全模糊的错误消息
public final class FailsWithMatcher
扩展类型安全匹配器{
除上述内容外,私人最终匹配者
如果将接口更改为…extends Exception,则可以引发如下错误:
@Override
protected boolean matchesSafely(final IThrowingRunnable<EX> runnable) {
try {
runnable.run();
throw new Error("Did not throw Exception");
} catch (final Exception ex) {
return matcher.matches(ex);
}
}
java.lang.Error: Did not throw Exception
at de.test.test.FailsWithMatcher.matchesSafely(FailsWithMatcher.java:31)
at de.test.test.FailsWithMatcher.matchesSafely(FailsWithMatcher.java:1)
at org.hamcrest.TypeSafeMatcher.matches(TypeSafeMatcher.java:65)
at org.hamcrest.MatcherAssert.assertThat(MatcherAssert.java:12)
at org.junit.Assert.assertThat(Assert.java:956)
at org.junit.Assert.assertThat(Assert.java:923)
at
...
我认为最简洁的方法是定义一个函数,比如
public static Throwable exceptionOf(Callable<?> callable) {
try {
callable.call();
return null;
} catch (Throwable t) {
return t;
}
}
也许还可以使用类似于的ExceptionMessageMatcher。您应该使用junit utils
,它确实包含一个ExceptionMatcher,可以与Hamcrest的assertThat()方法一起使用
例1:
assertThat(() -> MyObjectifyNoSuchFieldException.class,
throwsException(MyObjectifyNoSuchFieldException.class));
例2:
assertThat(() -> myObject.doStuff(null),
throwsException(MyObjectifyNoSuchFieldException.class)
.withMessageContaining("ERR-120008"));
此处的其他详细信息:Awesome@mystarrocks,谢谢。@Rule+ExceptedException方法如何比@Test(预期=…)更好方法?@MichaelOsofsky,最好是测试你认为这次可以抛出异常的确切方法调用。与方法级注释相比,方法级注释不会告诉你哪行抛出了给定的异常。假设我在你怀疑可以抛出给定异常的行之前有一行,则抛出相同的异常ion,您的测试实际上应该失败,但使用注释方法不会失败。@test
注释方法真正关心的是方法执行停止抛出给定的异常,而不是哪个调用真正抛出了该异常。更新了答案,解释了为什么此方法更好。另一个优点是您可以对异常消息进行断言:exceptionGrabber.expectMessage(“我的预期消息”);
它没有被注意到,或者可能我误读了某些内容,但您不想在该消息之后加上分号吗doSomething()
call?呵呵,JUnit当然没有一种成熟的方法来测试特定操作引发的错误……缺少针对失败的函数编程(在Java 8之前),您可以看看assertj库,它有一个优雅的api来断言异常:例如:assertThatThrownBy(()->{throw new Exception(“boom!”))}).isInstanceOf(Exception.class);如果将接口更改为…extends Exception,则可以抛出如下错误:完整代码如下:Nice消息将显示抛出的异常。对此我非常高兴。但不幸的是,我没有看到一种方法可以做到这一点,而不在matcher中创建存储状态,或者调用lambda两次,这通常会产生不同的结果:-(
assertThat(() -> MyObjectifyNoSuchFieldException.class,
throwsException(MyObjectifyNoSuchFieldException.class));
assertThat(() -> myObject.doStuff(null),
throwsException(MyObjectifyNoSuchFieldException.class)
.withMessageContaining("ERR-120008"));