携手创作,共同成长!这是我参与「掘金日新计划 · 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方法能很好的解决异常的验证和异常信息验证的问题。同时讲验证的粒度增强到了代码级别,比前面的几种方法粒度更细。前面的部分方法最小的验证粒度只能是方法级。

私信