SpringBoot JUnit 教程

📅 2026/7/6 4:11:28 👁️ 阅读次数 📝 编程学习
SpringBoot JUnit 教程

1. 核心依赖 (Maven)

<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency>

该 Starter 自动引入:

  • JUnit 5(Jupiter)

  • Mockito

  • AssertJ

  • Spring Test


2. 基础注解

注解作用
@SpringBootTest启动完整 Spring 上下文(集成测试)
@Test标记测试方法
@BeforeEach/@AfterEach每个测试前/后执行
@BeforeAll/@AfterAll所有测试前/后执行(需静态方法)
@DisplayName给测试起中文名
@Disabled禁用测试

3. 单元测试(Service 层)

被测 Service:

@Service public class UserService { public String getUserName(Long id) { return "user-" + id; } }

测试类:

@SpringBootTest class UserServiceTest { @Autowired private UserService userService; @Test @DisplayName("根据ID获取用户名") void testGetUserName() { String name = userService.getUserName(1L); assertEquals("user-1", name); assertNotNull(name); } }

4. Web 层测试(Controller)

使用@WebMvcTest只加载 Web 层,比@SpringBootTest轻量。

被测 Controller:

@RestController @RequestMapping("/api/users") public class UserController { @GetMapping("/{id}") public String getUser(@PathVariable Long id) { return "user-" + id; } }

测试类:

@WebMvcTest(UserController.class) class UserControllerTest { @Autowired private MockMvc mockMvc; @Test void testGetUser() throws Exception { mockMvc.perform(get("/api/users/1")) .andExpect(status().isOk()) .andExpect(content().string("user-1")); } }

5. Mock 依赖(隔离测试)

使用@MockBean模拟 Service,避免依赖真实数据库。

@SpringBootTest class UserControllerMockTest { @Autowired private MockMvc mockMvc; @MockBean private UserService userService; @Test void testGetUser() throws Exception { when(userService.getUserName(1L)).thenReturn("mock-user"); mockMvc.perform(get("/api/users/1")) .andExpect(status().isOk()) .andExpect(content().string("mock-user")); } }

6. 数据层测试(Repository)

使用@DataJpaTest测试 JPA,默认回滚事务。

@DataJpaTest class UserRepositoryTest { @Autowired private UserRepository userRepository; @Test void testSaveAndFind() { User user = new User("test"); userRepository.save(user); Optional<User> found = userRepository.findByName("test"); assertTrue(found.isPresent()); } }

7. 断言进阶(AssertJ)

import static org.assertj.core.api.Assertions.*; assertThat(user.getName()).startsWith("user"); assertThat(list).hasSize(3).contains("a", "b");

8. 测试生命周期

@TestInstance(TestInstance.Lifecycle.PER_CLASS) class LifecycleTest { @BeforeAll void initAll() { /* 无需 static */ } }

9. 常用 Mockito 操作

// 验证调用次数 verify(userService, times(1)).getUserName(anyLong()); // 抛出异常 when(userService.getUserName(1L)).thenThrow(new RuntimeException("error")); // 参数匹配 when(userService.getUserName(eq(1L))).thenReturn("user-1");

10. 测试覆盖率 (Jacoco)

<plugin> <groupId>org.jacoco</groupId> <artifactId>jacoco-maven-plugin</artifactId> <version>0.8.11</version> </plugin>

执行mvn clean test后生成target/site/jacoco/index.html


11. 最佳实践总结

类型推荐注解说明
单元测试(Service)@SpringBootTest可配合@MockBean
Web 层测试@WebMvcTest只加载 Controller
Repository 测试@DataJpaTest轻量,自动回滚
集成测试@SpringBootTest加载完整上下文
测试命名should_xxx_when_xxx清晰表达意图
断言AssertJ更丰富流畅

12. 面试常见问题

  1. @SpringBootTest@WebMvcTest区别?

    • @SpringBootTest:加载全部 Bean,适合集成测试。

    • @WebMvcTest:只加载 Web 层,更快。

  2. @MockBean@Mock区别?

    • @MockBean是 Spring 提供的,会将 Mock 对象注入 Spring 容器。

    • @Mock是 Mockito 的,不管理容器。

  3. 如何测试异步方法?
    使用@Async+CountDownLatchCompletableFuture配合await()