Java 后端手册JAVA BACKEND

CHAPTER 06生产层 · TESTING

测试与质量

JUnit 5、Mockito、Spring Test、Testcontainers 与覆盖率。让重构与服务演进有安全网。

开始阅读难度中级先修第四、五章约2小时
06.1

测试金字塔

大量快速单元测试、适量集成测试、少量端到端。优先测纯逻辑与边界,集成测跨层协作,E2E 只覆盖关键链路。

命名即文档

用 方法名_场景_预期(如 createOrder_insufficientStock_throws)命名测试,失败即知问题。

06.2

JUnit 5 基础

JUnit 5 用 @Test、@BeforeEach、assertThrows 等。断言用 Assertions,可读性强。

class CalculatorTest {
    private Calculator calc;
    @BeforeEach void setUp() { calc = new Calculator(); }

    @Test
    void add_positiveNumbers_returnsSum() {
        assertEquals(3, calc.add(1, 2));
    }
    @Test
    void divide_byZero_throws() {
        assertThrows(ArithmeticException.class, () -> calc.divide(1, 0));
    }
}
06.3

Mockito 模拟

Mockito 创建虚假依赖,定义其返回值并验证交互,让单测只聚焦被测类。配合 @ExtendWith(MockitoExtension.class)。

@ExtendWith(MockitoExtension.class)
class OrderServiceTest {
    @Mock InventoryRepository inventory;
    @InjectMocks OrderService service;

    @Test
    void create_decreasesStock() {
        when(inventory.decrease(anyLong(), anyInt())).thenReturn(true);
        service.create(new CreateOrderCmd(1L, 2, "a@b.com"));
        verify(inventory).decrease(1L, 2);   // 验证调用
    }
}
只 mock 边界依赖

内部纯逻辑直接测;只对数据库、第三方、时钟等外部依赖 mock,避免测试失真。

06.4

Spring 切片测试

用 @WebMvcTest(仅 Web 层)、@DataJpaTest(仅 JPA)、@SpringBootTest(全栈)按需加载上下文,加快测试。

@WebMvcTest(OrderController.class)
class OrderControllerTest {
    @Autowired MockMvc mvc;
    @MockBean OrderService service;
    // 只加载 Web 层,service 被 mock
}
06.5

MockMvc 测接口

MockMvc 在容器外模拟 HTTP 请求,断言状态码与响应体,覆盖 Controller 全链路(校验、异常处理)。

@Test
void get_existing_returns200() throws Exception {
    when(service.findById(1L)).thenReturn(new OrderDTO(1L));
    mvc.perform(get("/api/orders/1"))
       .andExpect(status().isOk())
       .andExpect(jsonPath("$.id").value(1));
}
06.6

Testcontainers

Testcontainers 在测试中拉起真实数据库/中间件容器,兼顾真实性与速度,适合集成测试关键数据路径。

@Container
static PostgreSQLContainer<?> db =
    new PostgreSQLContainer<>("postgres:16-alpine");

@Test
void save_and_read_roundtrip() {
    // 用真实 pg 连接测试 JPA 映射与查询
}
CI 需 Docker

Testcontainers 依赖本地或 CI 的 Docker 环境。纯单测应不依赖它,分层隔离。

06.7

覆盖率

Jacoco 统计行/分支覆盖。目标是关键路径高覆盖,而非盲目追 100%。配合 CI 门禁防止劣化。

<plugin>
  <groupId>org.jacoco</groupId>
  <artifactId>jacoco-maven-plugin</artifactId>
</plugin>
06.8

常见陷阱与 FAQ

测试间相互污染怎么办?

用 @BeforeEach 重建被测对象与状态,保证每个测试独立、可单独运行。

SpringBootTest 太慢?

只对真正需要完整上下文的用例用;其余用 @WebMvcTest/@DataJpaTest 等切片测试,大幅提速。

覆盖率高但仍有 bug?

覆盖率只说明"执行过",不说明"断言正确"。关注关键分支与业务断言质量。

06.9

实战练习与资源

延伸资源