Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/331.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
如何在Java中使用Hamcrest测试异常?_Java_Junit_Hamcrest - Fatal编程技术网

如何在Java中使用Hamcrest测试异常?

如何在Java中使用Hamcrest测试异常?,java,junit,hamcrest,Java,Junit,Hamcrest,如何使用Hamcrest测试异常?根据中的一条评论,“异常处理由JUnit4使用预期属性提供。” 所以我尝试了一下,发现它很有效: public class MyObjectifyUtilTest { @Test public void shouldFindFieldByName() throws MyObjectifyNoSuchFieldException { String fieldName = "status"; String field

如何使用Hamcrest测试异常?根据中的一条评论,“异常处理由JUnit4使用预期属性提供。”

所以我尝试了一下,发现它很有效:

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"));