相关文章
- 深入探索:单元测试之Test runners
- 深入探索:单元测试之基于 suites 的聚合测试
- 深入探索:单元测试之测试执行顺序
- 深入探索:单元测试之异常测试
- 深入探索:单元测试之Ignnore测试和TimeOut测试
- 深入探索:单元测试之Categories
- 深入探索:单元测试之Assertions
预期异常
如果我们测试知道这个方法是要抛出异常才是我们所期望的,不然就是测试失败,我们要如何验证呢?验证码完成通常是重要的,但是确保代码在特殊情况下的行为(如:异常,状态,超时,etc)同样重要。 举个例子:
new ArrayList<Object>().get(0);
这无疑无抛出IndexOutOfBoundsException,简称IOOBE。在@Test注解中,存在一个excepted参数,可以知道方法会抛出我们预期的异常。如果我们想去验证ArraryList 抛出正确的异常,我们可以这样写:
@Test(expected = IndexOutOfBoundsException.class)
public void empty() {
new ArrayList<Object>().get(0);
}
这个excepted 参数应该是我们所应该关心的,如果这个执行方法抛出IOOBE,那么这个方法将会通过测试。是不是用起来很简单,很爽。然而,这个方法并不是如理想中那么简单,万能的。其实官方推荐的是使用 ExceptedException rule, 来实现。
下面我举一个比较极端的一个例子吧! 如果我要测试一个方法,我遇见他会是超时的,终会抛出超时异常: 我们可以这样写:
@Test(timeout = 1000,expected = TestTimedOutException.class)
public void testA() {
System.out.println("first");
for (;;){}// 必然会抛出超时异常
}
我预测,他终会抛出异常超时,但是它仍然是无法通过测试的,这样的情况我们要如何做呢? 好吧,我们就试试project B, 按照官方推荐的试试:
@Rule
public ExpectedException thrown = ExpectedException.none();
@Test(timeout = 1000)
public void testB() {
thrown.expect(TestTimedOutException.class);
for(;;){}
}
这样就能完好的通过测试。当然,@Test(timeout=1000) 也是可以用** @Rule public Timeout globalTimeout = Timeout.seconds(1000); ** 来替代的,后面会讲到,大家耐心一点哈!
深入探索异常测试(使用@Rule)
上面的方法对简单的情况很有用,但也有它的局限性。例如,您不能在异常中测试消息的值,或者在抛出异常后对域对象的状态进行测试(如订单业务的 下单状态、支付状态、退款状态这种比较常见),etc。
Try/Catch 实现
在JUnit3.x 是通过 Try/Catch 来实现的
@Test
public void testExceptionMessage() {
try {
new ArrayList<Object>().get(0);
fail("Expected an IndexOutOfBoundsException to be thrown");
} catch (IndexOutOfBoundsException anIndexOutOfBoundsException) {
assertThat(anIndexOutOfBoundsException.getMessage(), is("Index: 0, Size: 0"));
}
}
ExpectedException Rule
另外,使用ExpectedException rule . 此规则不仅可以指示您期望的异常情况,还可以指示预期的异常消息:
@Rule
public ExpectedException thr = ExpectedException.none();
@Test
public void shouldTestExceptionMessage() throws IndexOutOfBoundsException {
List<Object> list = new ArrayList<Object>();
// 预测异常
thr.expect(IndexOutOfBoundsException.class);
thr.expectMessage("Index: 0, Size: 0");
list.get(0); // execution will never get past this line
}
也可以让你的expectmessage使用匹配器,这使你在你的测试更多的灵活性。一个例子:
thrown.expectMessage(Matchers.containsString("Size: 0"));
引入匹配器,需要org.hamcrest 的jar 包。 此外,您可以使用匹配检查异常,如果它具有嵌入式状态你想验证。例如:
import static org.hamcrest.Matchers.hasProperty;
import static org.hamcrest.Matchers.is;
import static org.hamcrest.Matchers.startsWith;
import javax.ws.rs.NotFoundException;
import javax.ws.rs.core.Response;
import javax.ws.rs.core.Response.Status;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;
public class TestExy {
@Rule
public ExpectedException thrown = ExpectedException.none();
@Test
public void shouldThrow() {
TestThing testThing = new TestThing();
thrown.expect(NotFoundException.class);
thrown.expectMessage(startsWith("some Message"));
thrown.expect(hasProperty("response", hasProperty("status", is(404))));
testThing.chuck();
}
private class TestThing {
public void chuck() {
Response response = Response.status(Status.NOT_FOUND).entity("Resource not found").build();
throw new NotFoundException("some Message", response);
}
}
}
来源:oschina
链接:https://my.oschina.net/u/1187675/blog/1533841