Java测试:单元测试、集成测试、端到端测试——完整指南

面向初学者的在线Python训练器

轻松学习Python,无需理论负担。在浏览器中直接解决带自动检查的实践任务,无需安装任何东西。

开始课程

Java 中的测试:从单元测试到端到端测试



代码质量是衡量开发者专业水平的关键指标之一。在 Java 世界中,测试早已不仅仅是一种良好实践,而是行业标准。没有可靠的测试,就很难维护大型项目、引入新功能以及自信地进行代码重构。在本文中,我们将探讨三个关键的测试层级:unit(单元测试)、integration(集成测试)和 e2e(端到端测试)。您将了解它们的区别、如何在 Java 中正确编写它们以及使用哪些工具。



测试金字塔及其重要性

在深入细节之前,有必要回顾一下 测试金字塔(Mike Cohn)的概念。它直观地展示了不同层级测试的理想比例:

  • Unit 测试(金字塔的基底)——速度最快、成本最低、数量最多。它们应占约 70%。
  • Integration 测试(中间层)——检查组件之间的交互。约占 20%。
  • E2E 测试(金字塔顶端)——速度最慢、成本最高,但对于验证用户场景至关重要。约占 10%。

遵循这一比例,可以在花费最少测试运行时间的情况下,对代码获得最大的信心。



1. Java 中的 Unit 测试

Unit 测试 隔离地测试代码的一个“单元”——通常是一个方法或类。其主要目标是确保方法的逻辑正确运行,而不依赖于外部依赖项(数据库、API、文件系统)。为了实现隔离,会使用 mock 对象。



主要工具

  • JUnit 5 —— 用于编写测试的标准框架。
  • Mockito —— 用于创建 mock 对象和验证交互的库。
  • AssertJ —— 用于 fluent 断言(提高可读性)的库。


使用 JUnit 5 和 Mockito 的 Unit 测试示例

假设我们有一个服务 UserService,它依赖于 UserRepository:

public class UserService {    private final UserRepository repository;        public UserService(UserRepository repository) {        this.repository = repository;    }        public User findById(Long id) {        return repository.findById(id)                .orElseThrow(() -> new UserNotFoundException("User not found"));    }}

针对该方法的测试:

import org.junit.jupiter.api.Test;import org.junit.jupiter.api.extension.ExtendWith;import org.mockito.InjectMocks;import org.mockito.Mock;import org.mockito.junit.jupiter.MockitoExtension;import java.util.Optional;import static org.junit.jupiter.api.Assertions.*;import static org.mockito.Mockito.*;

@ExtendWith(MockitoExtension.class)class UserServiceTest {

@Mock private UserRepository repository;

@InjectMocks private UserService userService;

@Test void testFindById_UserExists() { // Given Long userId = 1L; User expectedUser = new User(userId, "Alice"); when(repository.findById(userId)).thenReturn(Optional.of(expectedUser));

// When User actualUser = userService.findById(userId);

// Then assertNotNull(actualUser); assertEquals("Alice", actualUser.getName()); verify(repository).findById(userId); }

@Test void testFindById_UserNotFound() { // Given Long userId = 99L; when(repository.findById(userId)).thenReturn(Optional.empty());

// When & Then assertThrows(UserNotFoundException.class, () -> userService.findById(userId)); }}

最佳实践:

  • 测试单一

博客

书籍推荐