Mic*_*sky 11 java junit hamcrest
如何使用Hamcrest测试异常?根据https://code.google.com/p/hamcrest/wiki/Tutorial中的评论,"Junit 4使用期望属性提供了异常处理."
所以我尝试了这个,发现它有效:
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));
}
}
Run Code Online (Sandbox Code Playgroud)
Hamcrest是否提供了@Test(expected=...)
JUnit注释之外的任何其他功能?
虽然有人在Groovy中询问过这个问题(如何使用Hamcrest来测试异常?),我的问题是用Java编写的单元测试.
mys*_*cks 26
你真的需要使用这个Hamcrest
库吗?
如果没有,这就是你如何Junit
支持异常测试.ExpectedException
除了检查抛出的类型之外,该类还有许多方法可用于执行您想要的操作Exception
.
您可以将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);
...
}
}
Run Code Online (Sandbox Code Playgroud)
这种方法比
@Test (expected=...)
方法,因为@Test (expected=...)
只测试方法执行是否通过抛出给定的异常而停止,而不是如果你想抛出异常的调用抛出一个.例如,即使doSomething
方法抛出了MyObjectifyNoSuchFieldException
可能不合需要的异常,测试也会成功
您可以测试的不仅仅是抛出的异常类型.例如,您可以检查特定的异常实例或异常消息等
该try/catch
块方法,因为可读性和简洁.
rsl*_*mos 11
从 junit 4.13 开始,您可以使用它Assert.assertThrows
,如下所示:
import static org.junit.Assert.assertThrows;
...
MyObjectifyNoSuchFieldException ex = assertThrows(MyObjectifyNoSuchFieldException.class, () -> MyObjectifyUtil.getField(DownloadTask.class, fieldName));
// now you can go further and assert things about the exception ex
// if MyObjectifyUtil.getField(...) does not throw exception, the test will fail right at assertThrows
Run Code Online (Sandbox Code Playgroud)
在我看来,这种异常断言优于,@Test(expected=MyObjectifyNoSuchFieldException.class)
因为你可以:
如果计算断言错误描述,我无法以一种很好的方式实现它(这可能就是Hamcrest不提供这种功能的原因),但是如果您使用Java 8很好,那么您可能会想要这样的东西(但是我不这样做)认为由于以下问题,它永远不会使用):
此接口用于包装可能引发异常的代码。Callable<E>
可能也可以使用,但是后者需要返回一个值,因此我认为可运行(“ void-callable”)更为方便。
@FunctionalInterface
public interface IThrowingRunnable<E extends Throwable> {
void run()
throws E;
}
Run Code Online (Sandbox Code Playgroud)
此类实现匹配器,该匹配器要求给定的回调引发异常。此实现的缺点是,使回调引发意外的异常(甚至不引发单个异常)不会描述错误的原因,并且您会看到完全模糊的错误消息。
public final class FailsWithMatcher<EX extends Throwable>
extends TypeSafeMatcher<IThrowingRunnable<EX>> {
private final Matcher<? super EX> matcher;
private FailsWithMatcher(final Matcher<? super EX> matcher) {
this.matcher = matcher;
}
public static <EX extends Throwable> Matcher<IThrowingRunnable<EX>> failsWith(final Class<EX> throwableType) {
return new FailsWithMatcher<>(instanceOf(throwableType));
}
public static <EX extends Throwable> Matcher<IThrowingRunnable<EX>> failsWith(final Class<EX> throwableType, final Matcher<? super EX> throwableMatcher) {
return new FailsWithMatcher<>(allOf(instanceOf(throwableType), throwableMatcher));
}
@Override
protected boolean matchesSafely(final IThrowingRunnable<EX> runnable) {
try {
runnable.run();
return false;
} catch ( final Throwable ex ) {
return matcher.matches(ex);
}
}
@Override
public void describeTo(final Description description) {
description.appendText("fails with ").appendDescriptionOf(matcher);
}
}
Run Code Online (Sandbox Code Playgroud)
这是一个示例匹配器,用于对抛出的异常消息进行简单检查。
public final class ExceptionMessageMatcher<EX extends Throwable>
extends TypeSafeMatcher<EX> {
private final Matcher<? super String> matcher;
private ExceptionMessageMatcher(final Matcher<String> matcher) {
this.matcher = matcher;
}
public static <EX extends Throwable> Matcher<EX> exceptionMessage(final String message) {
return new ExceptionMessageMatcher<>(is(message));
}
@Override
protected boolean matchesSafely(final EX ex) {
return matcher.matches(ex.getMessage());
}
@Override
public void describeTo(final Description description) {
description.appendDescriptionOf(matcher);
}
}
Run Code Online (Sandbox Code Playgroud)
@Test
public void test() {
assertThat(() -> emptyList().get(0), failsWith(IndexOutOfBoundsException.class, exceptionMessage("Index: 0")));
assertThat(() -> emptyList().set(0, null), failsWith(UnsupportedOperationException.class));
}
Run Code Online (Sandbox Code Playgroud)
注意这种方法:
最糟糕的是,典型的失败看起来像
java.lang.AssertionError:
Expected: fails with (an instance of java.lang.IndexOutOfBoundsException and is "Index: 0001")
but: was <foo.bar.baz.FailsWithMatcherTest$$Lambda$1/127618319@6b143ee9>
Run Code Online (Sandbox Code Playgroud)
也许使用该assertThat()
方法的自定义实现可以解决该问题。
我想最干净的方法是定义一个像
public static Throwable exceptionOf(Callable<?> callable) {
try {
callable.call();
return null;
} catch (Throwable t) {
return t;
}
}
Run Code Online (Sandbox Code Playgroud)
某个地方然后打电话
assertThat(exceptionOf(() -> callSomethingThatShouldThrow()),
instanceOf(TheExpectedException.class));
Run Code Online (Sandbox Code Playgroud)
也许还使用类似于答案的ExceptionMessageMatcher之类的东西。
小智 5
您应该使用junit-utils
,它包含一个 ExceptionMatcher ,可以与 Hamcrest 的assertThat()
方法一起使用。
示例1:
assertThat(() -> MyObjectifyNoSuchFieldException.class,
throwsException(MyObjectifyNoSuchFieldException.class));
Run Code Online (Sandbox Code Playgroud)
示例2:
assertThat(() -> myObject.doStuff(null),
throwsException(MyObjectifyNoSuchFieldException.class)
.withMessageContaining("ERR-120008"));
Run Code Online (Sandbox Code Playgroud)
其他详细信息请参见:obvj.net/junit-utils
归档时间: |
|
查看次数: |
18301 次 |
最近记录: |