要验证异常消息我可以使用ExpectedMessage
对象但是如果我想验证concreate异常及其详细信息怎么办?例如,我有异常类TerribleWindException
,它有一些额外的方法,如getWindSpeed()
,在junit测试方法中,我想检查getWindSpeed()
结果。看看这个例子:
// pseudo implementation
public class TerribleWindException extends Exception {
private Integer windSpeed = 0;
public TerribleWindException(final Integer windSpeed) {
this.windSpeed = windSpeed;
}
}
public class WalkService {
private Integer windSpeed = 0;
public WalkService(final Integer windSpeed) {
this.windSpeed = windSpeed;
}
public void goForAWalk() throws TerribleWindException {
if (windSpeed>10) {
throw new TerribleWindException(windSpeed);
}
}
}
// test
public class WalkServiceTest {
@Test
public void testGoForAWalkWhenSpeedIsToPowerfulShouldThrowTerribleWindException throws TerribleWindException {
WalkService ws = new WalkService(100);
goForAWalk(); // this will throw TerribleWindException. The only way to check it's exception details is to use try {} catch() {} ?
}
}
检查异常详细信息的唯一方法是使用try {} catch(){}?
答案 0 :(得分:6)
您可以将JUnit' s ExpectedException rule与Hamcrest匹配器一起使用。
public class WalkServiceTest {
@Rule
public final ExpectedException thrown = ExpectedException.none();
@Test
public void testGoForAWalkWhenSpeedIsToPowerfulShouldThrowTerribleWindException throws TerribleWindException {
WalkService ws = new WalkService(100);
thrown.expect(TerribleWindException.class);
thrown.expect(Matchers.hasProperty("windSpeed", Matchers.equalTo("expected speed")));
ws.goForAWalk(); // this will throw TerribleWindException. The only way to check it's exception details is to use try {} catch() {} ?
}
}
如果您正在使用Java 8,那么您可以将Vallado library与Hamcrest一起使用。
public class WalkServiceTest {
@Test
public void testGoForAWalkWhenSpeedIsToPowerfulShouldThrowTerribleWindException throws TerribleWindException {
WalkService ws = new WalkService(100);
when(() -> ws.goForAWalk())
.thenA(TerribleWindException.class)
.that(hasProperty("windSpeed", equalTo("expected speed")))
.isThrown();
}
}
答案 1 :(得分:2)
对于这种情况,我建议您使用Google的catch-exception库,代码示例(来自他们的主页):
import static com.googlecode.catchexception.CatchException.*;
import static com.googlecode.catchexception.apis.CatchExceptionBdd.*;
// given: an empty list
List myList = new ArrayList();
// when: we try to get the first element of the list
when(myList).get(1);
// then: we expect an IndexOutOfBoundsException
then(caughtException())
.isInstanceOf(IndexOutOfBoundsException.class)
.hasMessage("Index: 1, Size: 0")
.hasNoCause();
如果上面的示例还不够,请参阅catch-exception AssertJ api。
答案 2 :(得分:1)
是。您可以使用@Test(expected=Exception.class)
注释来测试抛出的异常类,但要测试详细信息,您需要自己捕获并查询异常。
如果没有抛出异常,请不要忘记fail()
。 e.g。
try {
operation();
fail("Expected an exception");
}
catch (MyExpectedException e) {
// assertions...
}
答案 3 :(得分:1)
如果您使用Java 8,实际上有一种更灵活的方式来实现您想要的,它使用Lambdas。 以下步骤是必要的:
windSpeed
- 属性创建一个getter
为lambda创建一个函数接口,它不接受任何参数并且不返回任何内容,并且可能抛出异常,如下所示(Runnable不合适,因为它不会抛出异常而Callable有返回值):
@FunctionalInterface
public interface TestCommand {
public void exec() throws Exception;
}
为异常创建自己的断言,如下所示:
public <T extends Exception> void myAssertThrows(TestCommand testAction,
Predicate<T> p) {
try {
testAction.exec();
fail("must throw exception");
} catch (Exception exception) {
assertTrue(p.test((T) exception));
}
}
在测试中使用它:
@Test
public void testGoForAWalkWhenSpeedIsToPowerfulShouldThrowTerribleWindException(){
WalkService ws = new WalkService(10);
myAssertThrows(() -> {
ws.goForAWalk();
}, (TerribleWindException e) -> e.getWindSpeed() == 100);
}
那它是如何运作的? ws.goForAWalk();
被打包成TestCommand
类型的lambda,因此不会立即执行。它是myAssertThrows
的第一个参数,并在此方法中执行。第二个参数是Exception的谓词,它只是一个lambda,它将一个异常作为参数,返回一个布尔值,可用于检查引发的异常属性。 assert方法使用着名的try-catch-style。
您实际上也可以在Java 7中使用assert方法,但调用的可读性较差,因为它需要匿名类。
答案 4 :(得分:0)
您可以使用Junit的规则Junit Rules,其中包含ExpectedException规则,该规则也可用于测试异常消息。
编辑:
如果您通过以下方式实现TerribleWindException:
public class TerribleWindException extends Exception {
private Integer windSpeed = 0;
public TerribleWindException(final Integer windSpeed) {
// use Exception constructor, which passes a message
super("windSpeed: " + windSpeed);
this.windSpeed = windSpeed;
}
}
您可以使用此测试代码实现您想要的目标:
@Rule
public ExpectedException thrown = ExpectedException.none();
@Test
public void shouldTestExceptionMessage() throws IndexOutOfBoundsException {
List<Object> list = new ArrayList<Object>();
thrown.expect(TerribleWindException .class);
thrown.expectMessage("windSpeed: 100");
WalkService ws = new WalkService(100);
ws.goForAWalk();
}
答案 5 :(得分:0)
这个比我以前的答案更有意义,但我没有编辑我之前的答案,因为它适用于大多数用例。
ExpectedException规则允许您在测试中指定您期望的异常,甚至异常消息是什么
import static org.hamcrest.Matchers.*;
import static org.junit.Assert.*;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;
public class CloudTest {
@Rule
public ExpectedException exception = ExpectedException.none();
@Test
public void testExpectedException() {
exception.expect(CustomException.class);
exception.expectMessage(containsString('Invalid cloud type'));
new Cloud("Rainy","With thunder", "big");
}
}
答案 6 :(得分:-1)
我经常使用如下情况:
@Test
public void testGoForAWalkWhenSpeedIsToPowerfulShouldThrowTerribleWindException throws TerribleWindException {
WalkService ws = new WalkService(100);
try {
goForAWalk();
fail();
catch(TerribleWindException twe) {
}
}
答案 7 :(得分:-1)
不能通过使用以下模板来捕获特定的异常
@Test(expected= TerribleWindException.class)