本文目录导读:

在JUnit 5中,测试异常(Assertions for Exceptions)主要通过 org.junit.jupiter.api.Assertions 类中的 assertThrows 和 assertDoesNotThrow 方法来实现。
assertThrows - 断言抛出指定异常
assertThrows 是最常用的异常断言方法,它会验证被测试代码是否抛出了指定类型的异常。
基本用法
import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.assertThrows;
public class ExceptionTest {
@Test
void testThrowException() {
// assertThrows(异常类型, 可执行代码)
assertThrows(IllegalArgumentException.class, () -> {
// 这里应该抛出IllegalArgumentException的代码
throw new IllegalArgumentException("参数错误");
});
}
}
获取异常对象进行进一步断言
assertThrows 会返回捕获到的异常对象,可以用来进行更具体的验证:
@Test
void testExceptionMessage() {
// 获取异常对象
IllegalArgumentException exception = assertThrows(
IllegalArgumentException.class,
() -> {
throw new IllegalArgumentException("参数不能为负数");
}
);
// 验证异常消息
assertEquals("参数不能为负数", exception.getMessage());
// 验证异常的cause
assertNull(exception.getCause());
}
实际业务场景示例
public class Calculator {
public int divide(int a, int b) {
if (b == 0) {
throw new ArithmeticException("除数不能为0");
}
return a / b;
}
public void validateAge(int age) {
if (age < 0 || age > 150) {
throw new IllegalArgumentException("年龄必须在0-150之间");
}
}
public String getUserName(int userId) {
if (userId <= 0) {
throw new IllegalArgumentException("用户ID必须大于0");
}
// 模拟数据库查询
return "用户" + userId;
}
}
// 测试类
public class CalculatorTest {
private final Calculator calculator = new Calculator();
@Test
void testDivideByZero() {
ArithmeticException exception = assertThrows(
ArithmeticException.class,
() -> calculator.divide(10, 0)
);
assertEquals("除数不能为0", exception.getMessage());
}
@Test
void testValidateAgeInvalid() {
assertThrows(IllegalArgumentException.class,
() -> calculator.validateAge(-1));
assertThrows(IllegalArgumentException.class,
() -> calculator.validateAge(151));
}
@Test
void testGetUserNameWithNegativeId() {
Exception exception = assertThrows(
IllegalArgumentException.class,
() -> calculator.getUserName(-5)
);
assertTrue(exception.getMessage().contains("用户ID"));
}
}
assertDoesNotThrow - 断言不抛出异常
用于验证代码执行过程中没有抛出任何异常:
import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
@Test
void testNoException() {
assertDoesNotThrow(() -> {
// 这段代码不应该抛出异常
int result = 10 / 2;
});
}
@Test
void testSuccessfulOperation() {
assertDoesNotThrow(() -> {
calculator.validateAge(25);
});
}
多异常类型断言
@Test
void testMultipleExceptions() {
// 验证不同的输入导致不同的异常
assertThrows(IllegalArgumentException.class,
() -> calculator.validateAge(-1));
assertThrows(IllegalArgumentException.class,
() -> calculator.validateAge(151));
// 正常情况不抛出异常
assertDoesNotThrow(() -> calculator.validateAge(25));
}
异常链测试
@Test
void testExceptionChain() {
Exception exception = assertThrows(RuntimeException.class, () -> {
try {
throw new IOException("IO错误");
} catch (IOException e) {
throw new RuntimeException("运行时错误", e);
}
});
assertEquals("运行时错误", exception.getMessage());
assertNotNull(exception.getCause());
assertTrue(exception.getCause() instanceof IOException);
}
测试自定义异常
// 自定义异常
class BusinessException extends RuntimeException {
private final int errorCode;
public BusinessException(int errorCode, String message) {
super(message);
this.errorCode = errorCode;
}
public int getErrorCode() {
return errorCode;
}
}
// 测试
@Test
void testCustomException() {
BusinessException exception = assertThrows(
BusinessException.class,
() -> {
throw new BusinessException(1001, "业务异常");
}
);
assertEquals(1001, exception.getErrorCode());
assertEquals("业务异常", exception.getMessage());
}
使用 Lambda 表达式的高级用法
@Test
void testExceptionWithConditions() {
// 使用lambda表达式进行更复杂的验证
assertThrows(IllegalArgumentException.class, () -> {
// 复杂的业务逻辑
String input = "invalid";
if (input.length() > 5) {
throw new IllegalArgumentException("输入过长");
}
});
}
最佳实践
public class ExceptionTestBestPractices {
// 1. 明确测试目的
@Test
void shouldThrowExceptionWhenInputIsNegative() {
assertThrows(IllegalArgumentException.class,
() -> new Calculator().validateAge(-1));
}
// 2. 使用有意义的测试方法名
@Test
void divideByZero_ShouldThrowArithmeticException() {
assertThrows(ArithmeticException.class,
() -> new Calculator().divide(10, 0));
}
// 3. 避免过度使用assertThrows
@Test
void shouldNotThrowExceptionForValidInput() {
assertDoesNotThrow(() -> {
new Calculator().validateAge(30);
});
}
// 4. 测试边界值
@Test
void boundaryValueTesting() {
// 测试年龄边界值
assertThrows(IllegalArgumentException.class,
() -> new Calculator().validateAge(-1));
assertThrows(IllegalArgumentException.class,
() -> new Calculator().validateAge(151));
assertDoesNotThrow(() -> new Calculator().validateAge(0));
assertDoesNotThrow(() -> new Calculator().validateAge(150));
}
}
- assertThrows:验证代码抛出指定异常,可获取异常对象进行进一步检查
- assertDoesNotThrow:验证代码不抛出任何异常
- 异常链测试:可以测试异常的cause和层级关系
- 最佳实践:测试方法名要清晰,测试边界值,避免过度测试