Mokito 单元测试与 Spring-Boot 集成测试
版本说明
Java:1.8
JUnit:5.x
Mokito:3.x
H2:1.4.200
spring-boot-starter-test:2.3.9.RELEASE
通常任何软件都会划分为不同的模块和组件。单独测试一个组件时,我们叫做单元测试。单元测试用于验证相关的一小段代码是否正常工作。
单元测试不验证应用程序代码是否和外部依赖正常工作。它聚焦与单个组件并且 Mock 所有和它交互的依赖。
集成测试主要用于发现用户端到端请求时不同模块交互产生的问题。
集成测试范围可以是整个应用程序,也可以是一个单独的模块,取决于要测试什么。
典型的 Spring boot CRUD 应用程序,单元测试可以分别用于测试控制器(Controller)层、DAO 层等。它不需要任何嵌入服务,例如:Tomcat、Jetty、Undertow。
在集成测试中,我们应该聚焦于从控制器层到持久层的完整请求。应用程序应该运行嵌入服务(例如:Tomcat)以创建应用程序上下文和所有 bean。这些 bean 有的可能会被 Mock 覆盖。
单元测试
单元测试的动机,单元测试不是用于发现应用程序范围内的 bug,或者回归测试的 bug,而是分别检测每个代码片段。
几个要点
快,极致的快,500ms 以内
同一个单元测试可重复运行 N 次
每次运行应得到相同的结果
不依赖任何模块
Gradle 引入
引入 `spring-boot-starter-test` 做为测试框架。该框架已经包含了 JUnit5 和 Mokito 。
对 Service 层进行单元测试
工程结构
Domain 中定义 student 对象
Service 层定义 student 增加和检索的能力
Service 实现,单元测试针对该实现进行测试
创建单元测试,Mock 一切
@RunWith(MockitoJUnitRunner.class):添加该 Class 注解,可以自动初始化 @Mock 和 @InjectMocks 注解的对象。
MockitoAnnotations.initMocks():该方法为 @RunWith(MockitoJUnitRunner.class) 注解的替代品,正常情况下二选一即可。但是我在写单元测试的过程中发现添加 @RunWith(MockitoJUnitRunner.class) 注解不生效。我怀疑和 Junit5 废弃 @Before 注解有关,各位可作为参考。查看源码找到问题是更佳的解决方式。
@Spy:调用真实方法。
@Mock:创建一个标注类的 mock 实现。
@InjectMocks:创建一个标注类的 mock 实现。此外依赖注入 Mock 对象。在上面的实例中
StudentServiceImpl
被标注为 @InjectMocks 对象,所以 Mokito 将为StudentServiceImpl
创建 Mock 对象,并依赖注入Mapper
和StudentRepository
对象。
结果
集成测试
集成测试的目的是测试不同的模块一共工作能否达到预期。
集成测试不应该有实际依赖(例如:数据库),而是模拟它们的行为。
应用程序应该在 ApplicationContext 中运行。
Spring boot 提供 @SpringBootTest 注解创建运行上下文。
使用 @TestConfiguration 配置测试环境。例如 DataSource。
我们把集成测试集中在 Controller 层。
创建 Controller ,语法使用了 Kotlin 😈,提供 Create 和 Reitreve 能力
配置 H2 为数据源。并通过 schema.sql 创建 table,student_data.sql 初始化数据
schema.sql
student_data.sql
实现集成测试
@SpringBootTest:加载真实环境应用程序上下文
WebEnvironment.RANDOM_PORT:创建随机端口
@LocalServerPort:获取运行端口。
TestRestTemplate:发起 HTTP 请求。
结果
版权声明: 本文为 InfoQ 作者【Zhang】的原创文章。
原文链接:【http://xie.infoq.cn/article/c198cf951c182d3a9fddd6a8a】。文章转载请联系作者。
评论 (2 条评论)