> For the complete documentation index, see [llms.txt](https://yangsx95.gitbook.io/notes/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://yangsx95.gitbook.io/notes/architect/dan-yuan-ce-shi.md).

# 单元测试

一般认为，单元测试使用真正的外部依赖类，不访问数据库、外部缓存、消息中间件、网络服务、文件系统等等外部基础设施。如果访问了上面这些项目，应当归类到集成测试的范畴。如果是单元测试，就应该用测试替身（Mockito这样的库可以替你生成测试替身）替换掉所有的外部依赖。

如果要对具体的中间件以及服务，比如要测试数据库操作是否正确，应该优先使用本地或者内存服务，比如本地数据库或者内存数据库。

## 数据库操作

### 1. 不要使用共享数据库，要使用本地数据库，最好是内存数据库

传统的数据库单元测试通常需要连接到真实数据库并处理测试数据的插入、更新和删除\
这样会导致测试运行慢，并且留下了测试数据的残留。为了解决这个问题，你可以考虑使用嵌入式或内存数据库（如H2、HSQLDB或Derby）。这些数据库可以在内存中运行，以更快速和独立的方式进行测试，而不会影响到你的开发环境和数据库实例。

### 2. 如何隔离测试数据

为了确保每个测试之间的独立性，你可以在每个测试方法执行前后插入和清理测试数据。你可以使用JUnit的`@Before`和`@After`注解来定义在测试方法之前和之后执行的方法在`@Before`方法中，你可以插入测试数据，在`@After`方法中，你可以清理测试数据；这样可以保持每个测试方法的隔离性，避免不同方法之间的相互影响。

或者在测试用例开始之前，开启一个数据库事务，等到测试用例结束之后，回滚所提交的修改。

### 3. 使用数据库迁移工具

为了更方便地管理数据库结构和测试数据，你可以考虑使用数据库迁移工具（如Flyway或Liquibase）。这些工具可以帮助你创建和维护数据库结构，以及初始化和管理测试数据\
你可以在测试之前自动启动迁移，并且可以使用预定义的脚本来初始化测试数据。

### 4. 持久化层模拟

如果你的DAO层依赖于JDBC或其他ORM框架，你可以考虑使用模拟框架（如Mockito）来模拟数据库操作（因为我们可以认定框架的所有的数据操作都是正确的，无需测试），而不是实际连接和操作数据库。这样可以提高测试运行的速度，并减少对真实数据库的依赖性。

### 5. 增删改查的测试顺序问题

好的测试必须是独立的，不依赖于其他测试执行。一个测试不应该依赖另一个测试为他准备的数据或者设置的条件。

应在query测试中通过其他手段插入样例到数据库中，然后再执行query。可以使用DBUnit或者其他类似工具（或者使用flyway提前初始化到数据库中），将XML或者JSON格式的样例数据插入到数据库中。

如果一组测试都需要准备相同的样例数据，可以定义一个`@Before`的无参样例方法，在它里面填充样例数据代码。然后再定义一个`@After`方法来删除样例数据。
