6Growing Object-Oriented Software, Guided by Tests

维护测试

测试的可持续性

测试重构测试 smells测试隔离测试基础设施

🎯 AI 时代的学习建议:不要只读理论。理解这一章的设计动机(为什么需要这个概念?)和边界条件(什么情况下会失效?)。当 AI 生成的代码涉及这些概念时,你能判断它是否用对了场景。AI 能帮你总结内容,但无法替代你亲手阅读、思考、建立直觉的过程。

第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?

如何保持测试隔离?

测试基础设施包含什么?

如何安全地重构测试?

测试覆盖率目标应该是多少?


6/7维护测试
0%