第6章:维护测试(Maintaining the Test Suite)
一、导读
1.1 本章学习目标
第6章讲解如何维护测试的可持续性。测试代码和生产代码一样需要维护。
1.2 为什么第六章如此重要
测试如果不维护,就会变成负担。测试的 smells、脆弱性和基础设施问题都需要关注。
1.3 核心问题引导
测试有哪些常见的 smells?
如何保持测试的隔离性?
测试基础设施如何设计?
如何安全地重构测试?
二、核心概念详解
6.1 测试 Smells
常见测试 smells:
- 测试太多断言:一个测试验证太多东西
- 测试依赖顺序:测试之间有隐式依赖
- 测试太慢:阻碍开发速度
- 测试脆弱:微小的改动导致测试失败
- 测试不清晰:难以理解测试的意图6.2 测试隔离
java
// 反模式:测试共享状态
class SharedStateTest {
static List<String> items = new ArrayList<>();
@Test void test1() { items.add("a"); }
@Test void test2() { assertEquals(1, items.size()); } // 依赖 test1
}
// 正确做法:每个测试独立
class IsolatedTest {
@Test void test1() {
List<String> items = new ArrayList<>();
items.add("a");
assertEquals(1, items.size());
}
}6.3 测试基础设施
测试基础设施:
- 测试数据管理:Fixture、Factory
- Mock 框架:Mockito
- 断言库:AssertJ
- 测试工具:Testcontainers
好的基础设施让测试更容易编写和维护三、实战案例
6.1 重构测试
java
// 重构前:测试脆弱
@Test
public void testUserCreation() {
User user = new User("Alice", 30, "alice@test.com", "123456");
assertEquals("Alice", user.getName());
assertEquals(30, user.getAge());
assertEquals("alice@test.com", user.getEmail());
// 太多断言,改一个字段就失败
}
// 重构后:每个测试一个概念
@Test void shouldHaveName() {
User user = new User("Alice", 30);
assertEquals("Alice", user.getName());
}
@Test void shouldHaveAge() {
User user = new User("Alice", 30);
assertEquals(30, user.getAge());
}四、本章小结
测试需要持续维护。避免测试 smells,保持测试隔离,建设测试基础设施,安全地重构测试。
五、思考与练习
你的测试有哪些 smells?
如何保持测试隔离?
测试基础设施包含什么?
如何安全地重构测试?
测试覆盖率目标应该是多少?