springboot 单元测试_springboot单元测试
👉 单元测试是最基础的一层:不依赖 Spring,运行最快,价值最大。
1. 单元测试
单元测试(Unit Test)定义:
-
测试一个类的最小可测单元
-
不依赖 Spring
-
不访问数据库、文件系统、网络
-
通过模拟(Mock)替代外部依赖
特点:快、隔离、确保业务逻辑正确
2. Spring Boot 中单元测试依赖
虽然真正的单元测试不需要Spring,但通常使用Mockito + JUnit 5来Mock依赖:
在Maven里:
org.springframework.boot
spring-boot-starter-test
test
✅ 包含:
-
JUnit 5 (Jupiter)、Mockito、AssertJ、Hamcrest
3. 单元测试写法详解
3.1 不依赖Spring的最简单写法
示例类:
public class Calculator {
public int add(int a, int b) { return a + b; }
}
测试:
import org.junit.jupiter.api.Test;import static org.junit.jupiter.api.Assertions.assertEquals;class CalculatorTest { @Test void testAdd() { Calculator calculator = new Calculator(); assertEquals(5, calculator.add(2, 3)); } }
特点:
✅ 没有Spring注解
✅ 没有IOC容器
✅ 执行毫秒级
3.2 有依赖的服务,使用 Mockito
业务场景:
Service里依赖Repository:
@Service public class UserService { private final UserRepository userRepository; public UserService(UserRepository userRepository) { this.userRepository = userRepository; } public User getUserById(Long id) { return userRepository.findById(id).orElseThrow(() -> new NotFoundException()); } }
单元测试目标:
✅ 不启动Spring
✅ Mock UserRepository
测试写法:
import org.junit.jupiter.api.Test; import org.mockito.InjectMocks; import org.mockito.Mock; import org.mockito.junit.jupiter.MockitoExtension; import static org.mockito.Mockito.when; import static org.junit.jupiter.api.Assertions.*; @ExtendWith(MockitoExtension.class) class UserServiceTest { @Mock UserRepository userRepository; @InjectMocks UserService userService; @Test void testGetUserById() { User mockUser = new User(1L, \"Alice\"); when(userRepository.findById(1L)).thenReturn(Optional.of(mockUser)); User result = userService.getUserById(1L); assertEquals(\"Alice\", result.getName()); } }
✅ 依赖注入通过Mockito
✅ 无Spring Context启动
✅ 速度极快
4. 单元测试的Mock策略
Spring Boot推荐的单元测试Mock实践:
5. 为什么要Mock
✅ 隔离被测对象:UserServiceTest 只关心 UserService 的逻辑,不需要真正的数据库
✅ 提高速度:无IO
✅ 更容易写失败场景:模拟异常
✅ 可重复:永远稳定
6. @SpringBootTest
✅ 是Spring Boot官方推荐的集成测试注解
✅ 启动完整的Spring Application Context
✅ 模拟「像生产里那样」启动你的Spring Bean、配置、自动装配
特点:
-
测试的粒度:集成级
-
加载速度:相对慢
-
依赖注入:自动可用
-
非常适合测试Service层、Controller层、整体协作
@SpringBootTest 注解核心原理
✅ 解析@SpringBootApplication
✅ 加载完整的Spring上下文
✅ 自动注入Bean
✅ 支持@MockBean替换Bean
✅ 可以模拟Web容器(随机端口、本地端口)
@SpringBootTest 常见用途
✅ Service层集成测试
-
有些Service需要Autowired进来其他Service/Repository
-
用@MockBean来mock下游依赖
✅ Controller端到端测试
-
启动Web服务器
-
用TestRestTemplate/RestAssured真正发HTTP
✅ 全局配置测试
-
验证Spring Profile、Properties
✅ 事务测试
-
Spring Boot 测试默认有@Rollback
✅ 与Testcontainers结合
-
启动真实PostgreSQL/MySQL
7. 单元测试 vs 切片测试 vs 集成测试
Spring Boot里常见误区是把一切都用@SpringBootTest,这是集成测试,非常慢。
建议分层:
8. 推荐写法
✅ 80% 逻辑 → 纯单元测试
✅ 15% Spring 切片 → @WebMvcTest、@DataJpaTest
✅ 5% 全局集成 → @SpringBootTest / Testcontainers
9. 进阶:使用参数化测试
JUnit 5 支持:
@ParameterizedTest @CsvSource({\"1,2,3\", \"5,7,12\"}) void testAdd(int a, int b, int expected) { Calculator calc = new Calculator(); assertEquals(expected, calc.add(a, b)); }
✅ 避免重复代码
✅ 增加覆盖率
10. 单元测试常用断言库
✅ JUnit Assertions
✅ AssertJ (更好看、链式调用)
✅ Hamcrest
示例:
import static org.assertj.core.api.Assertions.assertThat; @Test void testSomething() { String result = \"hello\"; assertThat(result) .isNotNull() .startsWith(\"he\") .endsWith(\"lo\"); }
11. CI/CD流程:单元测试
Maven
mvn test
✅ 无Spring启动的单元测试 → 非常适合频繁在CI里跑
✅ 成本最低
✅ 总结
Spring Boot 单元测试=真正Java单元测试 + Mock依赖
✅ 不要动不动用 @SpringBootTest,它本质是集成测试,不是严格意义的单元测试
✅ 依赖外部组件要Mock
✅ 用正确层次,减少维护成本
✅ 让测试成为生产力,而不是负担