如果计算断言错误描述,我无法以一种很好的方式实现它(可能这就是为什么Hamcrest没有提供这样的功能),但是如果你玩得很好Java 8,那么你可能需要这样的东西(但是我认为由于下面描述的问题,它不会被使用):
IThrowingRunnable
此接口用于包装可能引发异常的代码。 也可以使用,但后者需要返回一个值,所以我认为一个runnable(“void-callable”)更方便。Callable<E>
@FunctionalInterface
public interface IThrowingRunnable<E extends Throwable> {
void run()
throws E;
}
FailWithMatcher
此类实现一个匹配器,该匹配器要求给定的回调引发异常。此实现的缺点是,回调引发意外异常(甚至没有引发单个异常)并不能描述错误所在,并且您会看到完全模糊的错误消息。
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);
}
}
异常消息匹配器
这是一个示例匹配器,用于对引发的异常消息进行简单检查。
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);
}
}
以及测试样品本身
@Test
public void test() {
assertThat(() -> emptyList().get(0), failsWith(IndexOutOfBoundsException.class, exceptionMessage("Index: 0")));
assertThat(() -> emptyList().set(0, null), failsWith(UnsupportedOperationException.class));
}
请注意,此方法:
- ...独立于测试运行程序
- ...允许在单个测试中指定多个断言
最糟糕的是,典型的失败会像这样
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>
也许使用该方法的自定义实现可以修复它。assertThat()