掌握JUnit 5测试框架的使用方法与测试最佳实践
JUnit 5是Java生态系统中最流行的单元测试框架,它提供了丰富的注解、断言方法和扩展机制。JUnit 5由三个子项目组成:JUnit Platform、JUnit Jupiter和JUnit Vintage,为现代Java应用提供了强大的测试支持。
@Test
void testMethod() {
// 测试方法
}
@BeforeEach
void setUp() {
// 每个测试前执行
}
assertEquals(expected, actual);
assertTrue(condition);
assertThrows(Exception.class, () -> {
// 可能抛出异常的代码
});
@ParameterizedTest
@ValueSource(strings = {"hello", "world"})
void testWithParameter(String argument) {
assertNotNull(argument);
}
JUnit 5提供了丰富的注解来控制测试的执行流程和行为,这些注解能够帮助我们构建结构化和可维护的测试代码。
注解 | 说明 | 使用场景 |
---|---|---|
@Test |
标记测试方法 | 基本测试方法 |
@BeforeEach |
每个测试前执行 | 测试数据准备 |
@AfterEach |
每个测试后执行 | 资源清理 |
@BeforeAll |
所有测试前执行一次 | 类级别初始化 |
@AfterAll |
所有测试后执行一次 | 类级别清理 |
@DisplayName |
自定义测试显示名称 | 提高可读性 |
@Disabled |
禁用测试 | 临时跳过测试 |
@ParameterizedTest |
参数化测试 | 多组数据测试 |
@RepeatedTest |
重复测试 | 压力测试 |
@Timeout |
超时测试 | 性能测试 |
以下是一个完整的JUnit 5测试示例,展示了各种测试注解、断言方法和测试技巧的使用。
/**
* 计算器类 - 用于演示单元测试
*
* 这个类提供基本的数学运算功能
* 包括加法、减法、乘法、除法等操作
*/
public class Calculator {
/**
* 加法运算
*/
public int add(int a, int b) {
return a + b;
}
/**
* 除法运算
*/
public double divide(int a, int b) {
if (b == 0) {
throw new IllegalArgumentException("除数不能为0");
}
return (double) a / b;
}
/**
* 计算阶乘
*/
public long factorial(int n) {
if (n < 0) {
throw new IllegalArgumentException("阶乘的参数不能为负数");
}
if (n == 0 || n == 1) {
return 1;
}
long result = 1;
for (int i = 2; i <= n; i++) {
result *= i;
}
return result;
}
}
import org.junit.jupiter.api.*;
import static org.junit.jupiter.api.Assertions.*;
/**
* Calculator类的单元测试
* 演示JUnit 5的各种测试注解和断言方法
*/
class CalculatorTest {
private Calculator calculator;
@BeforeAll
static void setUpClass() {
System.out.println("开始执行Calculator测试类");
}
@BeforeEach
void setUp() {
calculator = new Calculator();
System.out.println("创建Calculator实例");
}
@Test
@DisplayName("测试加法运算")
void testAdd() {
// 测试正数相加
assertEquals(5, calculator.add(2, 3));
assertEquals(0, calculator.add(-2, 2));
assertEquals(-5, calculator.add(-2, -3));
// 测试边界值
assertEquals(1, calculator.add(0, 1));
assertEquals(0, calculator.add(0, 0));
}
@Test
@DisplayName("测试除法运算")
void testDivide() {
assertEquals(2.0, calculator.divide(6, 3), 0.001);
assertEquals(2.5, calculator.divide(5, 2), 0.001);
assertEquals(-2.0, calculator.divide(-6, 3), 0.001);
}
@Test
@DisplayName("测试除零异常")
void testDivideByZero() {
IllegalArgumentException exception = assertThrows(
IllegalArgumentException.class,
() -> calculator.divide(5, 0)
);
assertEquals("除数不能为0", exception.getMessage());
}
@ParameterizedTest
@DisplayName("参数化测试加法")
@CsvSource({
"1, 2, 3",
"0, 0, 0",
"-1, 1, 0",
"10, -5, 5"
})
void testAddParameterized(int a, int b, int expected) {
assertEquals(expected, calculator.add(a, b));
}
@RepeatedTest(5)
@DisplayName("重复测试加法")
void testAddRepeated() {
assertEquals(4, calculator.add(2, 2));
}
@Test
@Timeout(1)
@DisplayName("超时测试")
void testTimeout() {
assertEquals(100, calculator.add(50, 50));
}
@Nested
@DisplayName("数学运算测试组")
class MathOperationsTest {
@Test
@DisplayName("组合断言测试")
void testCombinedAssertions() {
assertAll("基本运算",
() -> assertEquals(5, calculator.add(2, 3)),
() -> assertEquals(6, calculator.multiply(2, 3)),
() -> assertEquals(2.0, calculator.divide(6, 3))
);
}
}
}
@Test
@DisplayName("当输入两个正数时应该返回正确的和")
void shouldReturnSumWhenAddingTwoPositiveNumbers() {
// Arrange - 准备测试数据
Calculator calculator = new Calculator();
// Act - 执行被测试的方法
int result = calculator.add(2, 3);
// Assert - 验证结果
assertEquals(5, result);
}
@Test
void test1() {
// 测试多个不相关的功能
assertEquals(5, calculator.add(2, 3));
assertEquals(6, calculator.multiply(2, 3));
assertEquals("hello", stringUtils.reverse("olleh"));
}