携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第16天, 点击查看活动详情
在junit进行测试的过程中,有一类问题也是值得关注的,就是异常测试。代码在运行的过程中,某个分支需要抛出异常,在junit进行单元测试的时候要对这个分支的代码进行覆盖。本文介绍junit的异常测试过程。 被测试的代码如下:
public class Calculator {
public int add(int i,int j) throws Exception{
if(i < 0) {
throw new IllegalArgumentException("wrong i");
if(j < 0) {
throw new IllegalArgumentException("wrong j");
return i+j;
上述代码中,add方法,如果参数i和j有小于0的情况,就会抛出异常,并有对应的提示信息。
1.传统写法
对于单元测试中的传统写法,如果要测试异常,如下:
import org.junit.Test;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
public class ExceptionTest1 {
@Test
public void test1() {
Calculator calculator = new Calculator();
try {
calculator.add(-1, 1);
fail("no exception throw!");
} catch (Exception e) {
assertTrue(e instanceof IllegalArgumentException);
assertTrue(e.getMessage().contains("wrong i"));
@Test
public void test2() {
Calculator calculator = new Calculator();
try {
calculator.add(1, 1);
fail("no exception throw!");
} catch (Exception e) {
assertTrue(e instanceof IllegalArgumentException);
assertTrue(e.getMessage().contains("wrong i"));
需要在断言的时候,首先定义fail方法,之后再执行。test1用例执行结果如下:
再用例2中,如果没用出现异常:
这样就能拦截到异常是否发生。没用发生异常信息就会执行失败。如果不加fail方法,异常没有出现,我们是不知道的。
这种方式侵入性比较强,这种写法需要配合try-catch,也不是很优雅。因此这种方式来进行异常测试几乎被弃用了。junit4中引入了expected属性来解决这个问题。
2.注解expected属性方式
在Test注解中增加expected属性,来验证异常是否发生是junit4中比较常用的做法:
import org.junit.Test;
public class ExceptionTest2 {
@Test(expected = IllegalArgumentException.class)
public void test1() throws Exception {
Calculator calculator = new Calculator();
calculator.add(-1, 1);
@Test(expected = IllegalArgumentException.class)
public void test2() throws Exception {
Calculator calculator = new Calculator();
calculator.add(1, 1);
上述代码执行结果如下:
这种方式可以用来验证异常是否发生。
但是也有很大的局限性,首先无法验证异常抛出的具体消息。此外,如果一个测试用例里面出现了多个异常,或者有多个位置出现该异常,这个方式只能判断其中之一。
junit4.7之后采用了ExpectedException来增强。
3. ExpectedException 方式
采用ExpectedException方式如下:
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;
public class ExceptionTest3 {
@Rule
public ExpectedException expectedEx = ExpectedException.none();
@Test
public void test() throws Exception {
expectedEx.expect(IllegalArgumentException.class);
expectedEx.expectMessage("wrong i");
Calculator calculator = new Calculator();
calculator.add(-1, 1);
可以看到,定义了expectedEx ExpectedException,之后通过expectedEx的expect 和expectMessage方式来进行验证。上述代码执行结果:
最好的方式是采用Assert.assertThrows。
4. Assert.assertThrows
在junit4.13之后,增加了Assert.assertThrows断言来支持异常验证,可以验证异常类型和异常信息,具体方式如下:
import static org.junit.Assert.assertThrows;
public class ExceptionTest4 {
@Test
public void test1() {
Calculator calculator = new Calculator();
assertThrows(IllegalArgumentException.class, () -> {
calculator.add(-1, 1);
@Test
public void test2() {
Calculator calculator = new Calculator();
assertThrows("wrong i", IllegalArgumentException.class, () -> {
calculator.add(-1, 1);
上述代码执行结果:
assertThrows方法能很好的解决异常的验证和异常信息验证的问题。同时讲验证的粒度增强到了代码级别,比前面的几种方法粒度更细。前面的部分方法最小的验证粒度只能是方法级。