JUnit测试中如何断言抛出特定异常

JUnit测试中如何断言抛出特定异常

技术背景

在Java开发中,单元测试是确保代码质量和稳定性的重要手段。JUnit是Java开发中广泛使用的单元测试框架,在编写单元测试时,经常需要验证代码是否会抛出预期的异常。不同版本的JUnit以及搭配不同的断言库,有多种方式可以实现异常断言。

实现步骤

JUnit 5 和 JUnit 4.13+

可以使用 Assertions.assertThrows()(JUnit 5)和 Assert.assertThrows()(JUnit 4.13+):

import static org.junit.jupiter.api.Assertions.assertThrows;
import org.junit.jupiter.api.Test;

public class ExceptionTestingExample {
    @Test
    void exceptionTesting() {
        ArithmeticException exception = assertThrows(ArithmeticException.class, () ->
            calculator.divide(1, 0));

        assertEquals("/ by zero", exception.getMessage());
    }
}

JUnit 4.7+

可以使用 ExpectedException 规则:

import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;

public class FooTest {
    @Rule
    public final ExpectedException exception = ExpectedException.none();

    @Test
    public void doStuffThrowsIndexOutOfBoundsException() {
        Foo foo = new Foo();

        exception.expect(IndexOutOfBoundsException.class);
        foo.doStuff();
    }
}

经典的 try/catch 方式

import org.junit.Test;
import static org.junit.Assert.fail;

public class ExceptionTestingExample {
    @Test
    public void testFooThrowsIndexOutOfBoundsException() {
        try {
            foo.doStuff();
            fail("My method didn't throw when I expected it to");
        } catch (IndexOutOfBoundsException expectedException) {
        }
    }
}

使用 AssertJ 断言库

import static org.assertj.core.api.Assertions.*;
import org.junit.Test;

public class ExceptionTestingExample {
    @Test
    public void testFooThrowsIndexOutOfBoundsException() {
        Foo foo = new Foo();

        assertThatThrownBy(() -> foo.doStuff())
              .isInstanceOf(IndexOutOfBoundsException.class);
    }
}

核心代码

以下是不同方式的核心代码片段:

JUnit 5 异常断言

import static org.junit.jupiter.api.Assertions.assertThrows;
import org.junit.jupiter.api.Test;

public class JUnit5ExceptionTest {
    @Test
    void testException() {
        IllegalArgumentException exception = assertThrows(IllegalArgumentException.class, () -> {
            throw new IllegalArgumentException("a message");
        });
        assertEquals("a message", exception.getMessage());
    }
}

JUnit 4 ExpectedException 规则

import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;

public class JUnit4ExpectedExceptionTest {
    @Rule
    public ExpectedException thrown = ExpectedException.none();

    @Test
    public void testReadFile() throws FileNotFoundException {
        thrown.expect(FileNotFoundException.class);
        thrown.expectMessage(startsWith("The file test.txt"));
        myClass.readFile("test.txt");
    }
}

AssertJ 异常断言

import static org.assertj.core.api.Assertions.*;
import org.junit.Test;

public class AssertJExceptionTest {
    @Test
    public void testException() {
        assertThatThrownBy(() -> {
            throw new Exception("boom!");
        })
       .isInstanceOf(Exception.class)
       .hasMessageContaining("boom");
    }
}

最佳实践

  • JUnit 版本选择:如果使用 JUnit 5 或 JUnit 4.13+,优先使用 assertThrows 方法,它简洁且功能强大。
  • 异常信息验证:除了验证异常类型,还可以验证异常的消息、原因等信息,确保异常的准确性。
  • 代码可读性:选择合适的断言方式,使测试代码具有良好的可读性和可维护性。

常见问题

1. 使用 @Test(expected = ...) 的问题

这种方式只能断言方法抛出了指定异常,但不能精确到特定代码行。如果测试代码中多个地方可能抛出相同异常,可能会导致误判。

2. ExpectedException 规则的使用问题

  • ExpectedException 实例必须是 public 的。
  • 不能在 @Before 方法中实例化 ExpectedException

3. 名称冲突问题

使用 AssertJ 时,assertThat 可能会与 JUnit 的 assertThat 产生名称冲突,需要注意导入正确的包。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

1010n111

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值