一、JUnit 4 简介
JUnit 4 是 Java 社区最广泛使用的单元测试框架之一,4.13.2 版本是 JUnit 4 系列的最终版本。它通过注解和断言机制简化了单元测试的编写,成为 Java 开发中测试驱动开发(TDD)的基础工具。
二、核心组件架构
1. 核心类和接口
| 类/接口 | 功能描述 |
|---|---|
org.junit.Assert | 提供各种断言方法,用于测试验证 |
org.junit.Test | 标记方法为测试方法 |
org.junit.Before | 在每个测试方法前执行 |
org.junit.After | 在每个测试方法后执行 |
org.junit.BeforeClass | 在所有测试方法前执行(必须是静态方法) |
org.junit.AfterClass | 在所有测试方法后执行(必须是静态方法) |
org.junit.Ignore | 忽略指定的测试方法 |
org.junit.runner.RunWith | 指定自定义测试运行器 |
org.junit.rules.TestRule | 测试规则接口,允许灵活调整测试行为 |
三、注解详解与应用
1. 基础注解
@Test
@Test
public void standardTest() {
// 普通测试用例
}
@Test(expected = NullPointerException.class)
public void exceptionTest() {
String str = null;
str.length(); // 预期抛出NullPointerException
}
@Test(timeout = 100)
public void performanceTest() {
// 必须在100毫秒内完成
}
生命周期注解
@BeforeClass
public static void initClass() { /* 类初始化 */ }
@AfterClass
public static void cleanupClass() { /* 类清理 */ }
@Before
public void initTest() { /* 测试方法前执行 */ }
@After
public void cleanupTest() { /* 测试方法后执行 */ }
2. 进阶注解
@Ignore
@Ignore("待修复BUG-1234")
@Test
public void brokenTest() {
// 暂时跳过的测试
}
@RunWith
@RunWith(Parameterized.class)
public class AdvancedTest {
// 参数化测试实现
}
四、断言方法大全
基本断言
assertEquals("预期值", actual);
assertTrue(condition);
assertFalse(condition);
assertNull(object);
assertNotNull(object);
高级断言
assertSame(expectedObject, actualObject); // 对象引用相同
assertNotSame(unexpected, actual);
assertArrayEquals(expectedArray, actualArray);
fail("强制失败");
自定义错误消息
assertEquals("用户ID不匹配", expectedUserId, actualUserId);
五、测试规则(Rules)实战
1. TemporaryFolder
@Rule
public TemporaryFolder folder = new TemporaryFolder();
@Test
public void testFileOperations() throws IOException {
File file = folder.newFile("test.txt");
// 文件操作测试
}
2. ExpectedException
@Rule
public ExpectedException exception = ExpectedException.none();
@Test
public void testException() {
exception.expect(IllegalArgumentException.class);
exception.expectMessage("无效参数");
// 触发异常的代码
}
六、参数化测试模式
@RunWith(Parameterized.class)
public class FibonacciTest {
@Parameters
public static Collection<Object[]> data() {
return Arrays.asList(new Object[][] {
{0, 0}, {1, 1}, {2, 1}, {3, 2}, {4, 3}
});
}
private int input;
private int expected;
public FibonacciTest(int input, int expected) {
this.input = input;
this.expected = expected;
}
@Test
public void test() {
assertEquals(expected, Fibonacci.compute(input));
}
}
七、测试套件组织
@RunWith(Suite.class)
@Suite.SuiteClasses({
ServiceLayerTest.class,
DAOLayerTest.class,
UtilityTest.class
})
public class AllTestsSuite {
// 空类,仅作为套件容器
}
八、最佳实践示例
测试Calculator类
public class CalculatorTest {
private Calculator calc;
@Before
public void setUp() {
calc = new Calculator();
}
@Test
public void add_TwoNumbers_ReturnsSum() {
assertEquals(5, calc.add(2, 3));
}
@Test(expected = ArithmeticException.class)
public void divide_ByZero_ThrowsException() {
calc.divide(1, 0);
}
@Test(timeout = 50)
public void factorial_PerformanceTest() {
calc.factorial(20);
}
}
九、JUnit 4 生命周期
-
执行
@BeforeClass方法(仅一次) -
对于每个测试方法:
-
创建测试类实例
-
执行
@Before方法 -
执行当前
@Test方法 -
执行
@After方法
-
-
执行
@AfterClass方法(仅一次)
十、常见问题解决方案
-
测试顺序问题:JUnit 4 不保证测试方法的执行顺序,应确保测试独立性
-
静态字段共享:使用
@BeforeClass初始化共享资源 -
异常测试:优先使用
expected属性而非 try-catch -
耗时测试:合理设置
timeout值,避免测试套件执行过慢
结语
JUnit 4.13.2 虽然已被 JUnit 5 取代,但在众多遗留项目中仍广泛使用。掌握其核心功能对于维护现有项目和编写高质量单元测试至关重要。建议新项目优先考虑 JUnit 5,但对于维护现有测试代码,深入理解 JUnit 4 的特性仍然十分必要。

1265

被折叠的 条评论
为什么被折叠?



