我们写了一个方法,这个方法可能会抛出异常。针对这类方法,我们该怎么写单元测试呢?我们先思考一个问题,我们的测试用例是啥样的?
- 用例一: 当满足某条件的时候应该抛出异常,如果没有异常,那么大概率是我们的目标测试方法内部的实现有问题。
- 用例二: 当满足某条件的时候应该正常执行拿到结果,不应该抛出异常,如果抛出了异常,那么大概率是我们的目标测试方法内部没有
try catch
住异常
所以,我们得从正反两方面来考虑写单元测试。一面是应该抛异常,一面是不应该抛异常。
例如
public class TargetCode {
public static int divide(int a, int b) {
if (b == 0) {
throw new ArithmeticException("除数不能为0");
}
return a / b;
}
}
对应的单元测试
import org.junit.Test;
import static org.junit.Assert.*;
public class TargetCodeTest {
//我们要测试一个会抛出异常的。如果没有抛出异常这个单元测试是通过不了的
@Test(expected = ArithmeticException.class)
public void testDivideByZero() {
int a = 10;
int b = 0;
TargetCode.divide(a, b);
}
//还要测试一个正常场景下不会抛出异常的。如果抛出异常,这个单元测试是通过不了
@Test
public void testDivide() {
int a = 10;
int b = 2;
int result = TargetCode.divide(a, b);
assertEquals(5, result);
}
}
我们该try catch么?有人说我直接try catch
不行么。不行,try catch 住了之后,只能校验抛出了异常的情况,但是针对可能因为代码出错而导致没有抛异常这样的场景无法测试到。如果只是想测试这个方法在特定场景下会抛出异常,直接用 @Test(expected=XXXExcepting.class)
就好了。但是有的时候我们需要测试抛出的异常的报文是什么,这时候有两种手段,第一种是使用 @Rule
第二种是使用 Assert.assertThrows
。不过 @Rule
已经在新版本的junit中标记为废弃了,进而推荐使用 Assert.assertThrows
这种形式。
方式一: @Rule
示例
@Rule
private final ExpectedException exception = ExpectedException.none();
@Test
public void testLoginWhenAccountPassIsBlank() {
exception.expect(IllegalArgumentException.class);
exception.expectMessage("accountPass can not be blank");
AccountLoginRequest accountLoginRequest = new AccountLoginRequest();
accountLoginRequest.setAccountName("mock");
loginService.login(accountLoginRequest);
}
方式二: Assert.assertThrows
示例
@Test
public void testLoginWhenAccountNameIsBlank() {
IllegalArgumentException illegalArgumentException = Assert.assertThrows(IllegalArgumentException.class, () -> {
AccountLoginRequest accountLoginRequest = new AccountLoginRequest();
loginService.login(accountLoginRequest);
});
String message = illegalArgumentException.getMessage();
Assert.assertEquals("accountName can not be blank", message);
}