一, spring boot 应用测试存在的问题
官方提供的测试框架 spring-boot-test-starter, 虽然提供了很多功能(junit,spring test,assertj,hamcrest,mockito,jsonassert,jsonpath), 但是在数据库层面, 依旧存在问题, 它强烈依赖于数据库中的数据, 并且自身不具备数据初始化的能力. 测试框架 spring-test-dbunit 与 spring-boot-unitils-starter 支持 spring-boot 应用的测试, 同时, 也提供单元测试前置数据准备的功能.
二, spring-test-dbunit 介绍与应用
2.1, 介绍
spring-test-dbunit 是 spring boot 的作者之一 Phillip webb 开发的, 用于给 spring 项目的单元测试提供 dbunit 功能的开源项目. dbunit 项目的介绍为: puts your database into a known state between test runs.spring-test-dbunit 的官网介绍为: Spring DBUnit provides integration between the Spring testing framework and the popular DBUnit project.
2.2, 应用
实例主要代码如下:
- @RunWith(SpringJUnit4ClassRunner.class)
- @SpringBootTest(classes = DemoTestApplication.class)
- @TestExecutionListeners({
- DependencyInjectionTestExecutionListener.class,
- TransactionDbUnitTestExecutionListener.class})
- @DbUnitConfiguration(dataSetLoader = XlsDataSetLoader.class)
- @Transactional
- public class UserControllerTest {
- @Autowired
- private UserController userController;
- @Test
- @DatabaseSetup({"/data/test_getUsername.xls"})
- public void test_getUsername() {
- String username = userController.getUsername(1234);
- Assert.assertTrue(username.equals("zhangsan"));
- }
- }
test_getUsername.xls 的内容如下:
2.3, 实现原理
测试环境准备:
@RunWith(SpringJUnit4ClassRunner.class): 用于启动测试, 注册 TestExecutionListener, 构建 testContext.
@SpringBootTest(classes = DemoTestApplication.class): 利用 SpringBootTestContextBootstrapper 加载 applicationContext.
DependencyInjectionTestExecutionListener: 用来将 bean 注入到测试的 class 中, 例如实例中的 userController.
事务实现原理:
这里的 TransactionalTestExecutionListener 简称 T,DbUnitTestExecutionListener 简称 D, 如下图:
运行流程为: 初始化测试类 -->开始事务 -->准备测试数据 -->运行测试方法 -->进行 expectedData 校验 -->回滚或者提交事务. 这就保证了整个方法的测试过程中, 数据准备, 测试方法运行, 测试数据校验都在一个事务里面, 最后事务如果回滚了, 就不会在测试数据库中留下测试数据.
三, spring-boot-unitils-starter 介绍与应用
3.1, 介绍
unitils 框架介绍: Unitils is an open source library aimed at making unit and integration testing easy and maintainable. 堪称测试之王, 其组成结构如下:
unitils 目前只支持 xml 配置的 spring 项目, 对于 spring-boot 项目稍不支持, 基于此, 我就开源一个项目, 用于在 unitils 和 spring-boot 应用之间建立起桥梁.
这个开源项目主要做了以下工作:
重写 SpringModule->SpringBootModule, 支持 ApplicationContext 的设置 ApplicationContext 设置到 SpringBootModule 中 DataSource 替换支持 xls 的 dataSet
目前可用的版本为:
- <dependency>
- <groupId>com.GitHub.yangjianzhou</groupId>
- <artifactId>spring-boot-unitils-starter</artifactId>
- <version>1.1.0.RELEASE</version>
- </dependency>
3.2, 应用
实例代码如下:
- @RunWith(UnitilsBootBlockJUnit4ClassRunner.class)
- @SpringBootTest(classes = DemoTestApplication.class)
- @Transactional(value = TransactionMode.ROLLBACK)
- public class UserControllerTest {
- @SpringBeanByType
- private UserController userController;
- @Test
- @DataSet({"/data/test_getUsername.xls"})
- public void test_getUsername() {
- String username = userController.getUsername(1234);
- Assert.assertTrue(username.equals("zhangsan"));
- }
- }
3.3, 实现原理
DatabaseModule 下的 DatabaseTestListener 进行了事务的开启与回滚(提交).
DbUnitModule 下的 DbUnitListener 进行了 dataset 的准备与 expecteddataset 的校验.
SpringBootModule 下的 SpringTestListener 进行了测试类中属性的注入与销毁测试类.
四, 扩展
与 spring-boot-unitils-starter 弥补了 spring-boot-test-starter 在数据库测试方面的不足, 结合框架 spring-test-dbunit(或者 spring-boot-unitils-starter)与 mock 工具 (mockito) 以及一些测试方法, 可以很好的完成单元测试.
但是, spring-test-dbunit 与 spring-boot-unitils-starter 各有优缺点, spring-test-dbunit 有良好的文档, 但是最近更新版本为 2016 年版, 仅仅是数据库层面的测试工具. spring-boot-unitils-starter 利用了 unitils 的优势, 可以说是一个测试平台了, 虽然说, 每年都在发布版本(unitils), 但是其文档较少. 用户可以根据自己的需要进行选择.
附: 文中涉及到的测试样例代码:
来源: https://yq.aliyun.com/articles/692990