164 lines
3.9 KiB
Markdown
164 lines
3.9 KiB
Markdown
# Spring Boot 单元测试学习示例(基于JDBC)
|
||
|
||
这是一个完整的Spring Boot单元测试学习项目,演示了如何使用JUnit 5和Mockito编写高质量的单元测试。
|
||
项目使用纯JDBC方式(非JPA),更贴近传统的数据库操作方式。
|
||
|
||
## 项目结构
|
||
|
||
```
|
||
src/
|
||
├── main/java/com/example/usertest/
|
||
│ ├── entity/ # 实体类
|
||
│ ├── dto/ # 数据传输对象
|
||
│ ├── repository/ # 数据访问层接口
|
||
│ │ ├── UserRepository.java # Repository接口
|
||
│ │ └── JdbcUserRepository.java # JDBC实现示例
|
||
│ ├── service/ # 业务逻辑层
|
||
│ ├── exception/ # 自定义异常
|
||
│ └── config/ # 配置类
|
||
├── main/resources/
|
||
│ ├── application.properties # 应用配置
|
||
│ └── schema.sql # 数据库表结构(仅供参考)
|
||
└── test/java/com/example/usertest/
|
||
└── service/ # 单元测试类
|
||
```
|
||
|
||
## 技术栈
|
||
|
||
- **Spring Boot 3.1.5**
|
||
- **Java 17**
|
||
- **JUnit 5** - 测试框架
|
||
- **Mockito** - Mock框架
|
||
- **AssertJ** - 断言库
|
||
- **Maven** - 构建工具
|
||
|
||
## 核心功能
|
||
|
||
UserService提供以下业务功能:
|
||
1. **用户注册** (`registerUser`)
|
||
2. **用户登录** (`loginUser`)
|
||
3. **修改密码** (`changePassword`)
|
||
4. **删除用户** (`deleteUser`)
|
||
5. **获取用户信息** (`getUserById`)
|
||
|
||
## 测试覆盖
|
||
|
||
单元测试覆盖了以下场景:
|
||
|
||
### 正常场景测试
|
||
- 成功注册新用户
|
||
- 成功登录
|
||
- 成功修改密码
|
||
- 成功删除用户
|
||
- 成功获取用户信息
|
||
|
||
### 异常场景测试
|
||
- 用户名/邮箱已存在
|
||
- 用户不存在
|
||
- 密码错误
|
||
- 输入验证失败
|
||
- 空值处理
|
||
|
||
### 边界条件测试
|
||
- 用户名长度边界(3-20字符)
|
||
- 密码长度边界(6-20字符)
|
||
- 特殊字符处理
|
||
|
||
### Mock验证测试
|
||
- 方法调用次数验证
|
||
- 方法调用顺序验证
|
||
- 参数验证
|
||
|
||
## 如何运行
|
||
|
||
### 1. 克隆项目
|
||
```bash
|
||
git clone <repository-url>
|
||
cd springboot-test
|
||
```
|
||
|
||
### 2. 运行所有测试
|
||
```bash
|
||
mvn test
|
||
```
|
||
|
||
### 3. 运行特定测试
|
||
```bash
|
||
# 运行特定测试类
|
||
mvn test -Dtest=UserServiceTest
|
||
|
||
# 运行特定测试方法
|
||
mvn test -Dtest=UserServiceTest#registerUser_Success
|
||
```
|
||
|
||
### 4. 生成测试报告
|
||
```bash
|
||
mvn surefire-report:report
|
||
```
|
||
|
||
## 关键学习点
|
||
|
||
### 1. 测试注解
|
||
- `@ExtendWith(MockitoExtension.class)` - 启用Mockito
|
||
- `@Mock` - 创建模拟对象
|
||
- `@InjectMocks` - 注入依赖
|
||
- `@Nested` - 组织测试
|
||
- `@DisplayName` - 测试描述
|
||
|
||
### 2. 测试模式
|
||
```java
|
||
@Test
|
||
void testMethod() {
|
||
// Given - 准备测试数据
|
||
// When - 执行测试
|
||
// Then - 验证结果
|
||
}
|
||
```
|
||
|
||
### 3. Mock使用
|
||
```java
|
||
// 定义行为
|
||
when(repository.findById(1L)).thenReturn(Optional.of(user));
|
||
|
||
// 验证调用
|
||
verify(repository).save(any(User.class));
|
||
|
||
// 捕获参数
|
||
ArgumentCaptor<User> captor = ArgumentCaptor.forClass(User.class);
|
||
verify(repository).save(captor.capture());
|
||
```
|
||
|
||
### 4. 断言示例
|
||
```java
|
||
// 基本断言
|
||
assertThat(result).isNotNull();
|
||
assertThat(result.getUsername()).isEqualTo("testuser");
|
||
|
||
// 异常断言
|
||
assertThatThrownBy(() -> service.method())
|
||
.isInstanceOf(ValidationException.class)
|
||
.hasMessage("Error message");
|
||
```
|
||
|
||
## 最佳实践
|
||
|
||
1. **单一职责**: 每个测试只验证一个功能点
|
||
2. **独立性**: 测试之间相互独立
|
||
3. **可读性**: 使用描述性的测试名称
|
||
4. **完整性**: 覆盖正常和异常场景
|
||
5. **可维护性**: 使用常量避免硬编码
|
||
|
||
## 扩展学习
|
||
|
||
- 集成测试 (`@SpringBootTest`)
|
||
- 数据库测试 (`@DataJpaTest`)
|
||
- Web层测试 (`@WebMvcTest`)
|
||
- 测试容器 (Testcontainers)
|
||
- 性能测试 (JMH)
|
||
|
||
## 参考资源
|
||
|
||
- [Spring Boot Testing](https://spring.io/guides/gs/testing-web/)
|
||
- [JUnit 5 User Guide](https://junit.org/junit5/docs/current/user-guide/)
|
||
- [Mockito Documentation](https://javadoc.io/doc/org.mockito/mockito-core/latest/org/mockito/Mockito.html)
|
||
- [AssertJ Documentation](https://assertj.github.io/doc/) |