我将尝试提供一个陈词滥调,无用的例子,很好地减少问题:-)
我有一个GenericException
,和一个延伸GenericException
的MoreSpecificException
。
我需要测试SomeService.doThis()
抛出MoreSpecificException
.JUnit让我像这样优雅地做到这一点。
@Test(expected = MoreSpecificException.class)
public void testDoThis() throws GenericException {
new SomeService().doThis();
}
但是,我还需要测试SomeService.doThat()
抛出GenericException
,所以我尝试了这个。
@Test(expected = GenericException.class)
public void testDoThat() throws GenericException {
new SomeService().doThat();
}
但是,我发现如果doThat()
真的抛出了一个MoreSpecificException
那么第二个测试仍然通过。我认为这是因为MoreSpecificException
是一个GenericException
并且实现注释是为了尊重这种关系。
虽然这是一个明智的默认行为,但我不希望这样。我想测试一下doThat()
抛出GenericException
,而且只有一个GenericException
.如果它抛出MoreSpecificException
或GenericException
的任何其他子类,我希望测试失败。
阅读文档时,我似乎无法对注释做任何事情来更改此行为,因此看起来我将不得不使用另一种解决方案。
目前,我正在采用以下丑陋的解决方案 - 内森休斯的回答使编辑变得不那么丑陋:-)
@Test
public void testDoThat() {
try {
new SomeService().doThat();
Assert.fail();
} catch(GenericException ex) {
Assert.assertEquals(GenericException.class, ex.getClass());
}
}
在 JUnit 框架中,有没有更优雅的方式来实现我想要的东西?
BDD 样式解决方案
JUnit 4 + 捕获异常 + 断言J
最优雅的解决方案;)可读,无样板代码。
@Test
public void testDoThat() {
when(new SomeService()).doThat();
then(caughtException()).isExactlyInstanceOf(GenericException.class);
}
对于 FEST 断言 2 + 捕获异常,代码是相同的。
源代码
- https://gist.github.com/mariuszs/7489706
依赖
org.assertj:assertj-core:1.4.0
com.googlecode.catch-exception:catch-exception:1.2.0
您可以断言异常的类是您所期望的:
@Test
public void testDoThat() {
try {
new SomeService().doThat();
Assert.fail();
} catch(GenericException ex) {
assertEquals(GenericException.class, ex.getClass());
}
}
还摆脱了标志,而是在没有抛出异常的情况下让测试失败。
ExpectException 规则和指定可以抛出哪个类的自定义 Hamcrest 匹配器。
以下测试将打印出您期望的 RuntimeException 实例,但得到 IllegalArgumentException。
@Rule
public ExpectedException thrown = ExpectedException.none();
@Test
public void testThrows() {
thrown.expect(isClass(RuntimeException.class));
throw new IllegalArgumentException("FAKE");
}
public class ClassMatchMatcher extends BaseMatcher<Object> {
private final Class<?> expectedClass;
private ClassMatchMatcher(Class<?> expectedClass) {
this.expectedClass = expectedClass;
}
@Override
public boolean matches(Object item) {
return expectedClass.equals(item.getClass());
}
@Override
public void describeTo(Description description) {
description.appendText("an instance of ")
.appendText(expectedClass.getName());
}
}
public class ExtraMatchers {
public static Matcher<Object> isClass(Class<?> aClass) {
return new ClassMatchMatcher(aClass);
}
}
编辑:添加静态工厂方法以使测试代码更清晰。