在编写单测的过程中,我们应该尽可能的减少单测实例对第三方组件/服务的依赖。本章主要讲解springboot如何通过dbunit+h2实现脱离数据库独立执行单测实例。
1、pom.xml添加依赖,springboot默认已配置相关版本,只需要直接引入依赖即可
<!-- 单测依赖模块 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.dbunit</groupId>
<artifactId>dbunit</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.github.springtestdbunit</groupId>
<artifactId>spring-test-dbunit</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.h2database</groupId>
<artifactId>h2</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.powermock</groupId>
<artifactId>powermock-module-junit4</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.powermock</groupId>
<artifactId>powermock-api-mockito2</artifactId>
<scope>test</scope>
</dependency>
2、在test目录新建resources目录,并设置为“Test Resources”,
3、在test/resources目录新建目录:ddl、dml、preparedata;
4、在test/resources目录新建yml文件:application-unit.yml(也可以拷贝工程已使用的配置文件),加入以下配置:
# datasource
spring:
application:
name: demo-test
datasource:
driver-class-name: org.h2.Driver
url: jdbc:h2:mem:bone;DB_CLOSE_DELAY=-1;MODE=MYSQL
username: root
password: root
schema: classpath:/ddl/schema.sql
data: classpath:/dml/*.sql
initialization-mode: always
注:
- spring:datasource:schema: 表示启动前执行的脚本,放置建表语句;
- spring:datasource:data: 放置启动前执行的DML脚本;
5、创建基类:BaseTest(注意:ActiveProfiles的使用)
import com.github.springtestdbunit.DbUnitTestExecutionListener;
import org.junit.Assert;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.annotation.DirtiesContext;
import org.springframework.test.context.ActiveProfiles;
import org.springframework.test.context.TestExecutionListeners;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.test.context.support.DependencyInjectionTestExecutionListener;
import org.springframework.test.context.support.DirtiesContextTestExecutionListener;
import org.springframework.test.context.transaction.TransactionalTestExecutionListener;
/**
* @author nuoka
* @version 1.0
* @date 2019/9/8 14:32
* <ul>
* <li>https://www.jianshu.com/p/bdc0d109e643</li>
* <li>@ContextConfiguration: 加载配置</li>
* <li>@TestExecutionListeners: 指定在测试类执行之前,可以做的一些动作</li>
* <li>@DirtiesContext: 测试类的所有测试执行结束后,该测试的application context会被关闭,同时缓存会清除</li>
* </ul>
*/
@RunWith(SpringJUnit4ClassRunner.class)
@DirtiesContext(classMode = DirtiesContext.ClassMode.AFTER_EACH_TEST_METHOD)
@TestExecutionListeners({DependencyInjectionTestExecutionListener.class,
DirtiesContextTestExecutionListener.class,
TransactionalTestExecutionListener.class,
DbUnitTestExecutionListener.class})
@SpringBootTest(classes = DemoTestApplication.class)
@ActiveProfiles(profiles = "unit")
public abstract class BaseTest {
@Test
public void name() {
Assert.assertTrue(Boolean.TRUE);
}
}
6、单测类继承BaseTest,run test即可。实现原理说透其实是把存储介质由mysql切换到h2,所以原有单测代码不需要做其他改动,唯一要做的就是集成BaseTest。
7、前面的步骤看着都相对的简单,下面开始填坑:
- ddl.sql的编写非常费劲,博主是把mysql的数据结构全局导出,一点点的调整到完全兼容h2才能完美运行,mysql有很多关键字(comment,等)在h2并没有得到兼容,具体细节建议call百度姐姐,下面是博主的一个建表脚本,可参考使用:
drop table if exists `T_SYS_DICT`;
CREATE TABLE `T_SYS_DICT` (
`DICT_ID` varchar(32) NOT NULL,
`DICT_CODE` varchar(32) NOT NULL,
`DICT_TYPE` varchar(32) NOT NULL,
`DICT_NAME` varchar(100) NOT NULL,
`PARENT_DICT_CODE` varchar(100) DEFAULT NULL,
`SORT_NO` int(4) NOT NULL
PRIMARY KEY (`DICT_ID`)
) DEFAULT CHARSET=utf8;
- dml目录主要用来放置初始化的数据(inset 语句),单测启动会自动扫描并执行,这可以省去很多功夫,但数据准备也费劲,而且需要长时间维护,不建议放置太多的测试数据,只需要满足单测执行需求即可;
针对部分特殊的单测,dml初始化的数据无法满足使用,可定义到preparedata目录,原则上应尽可能保证测试数据的纯洁、准确。
<?xml version="1.0" encoding="UTF-8"?>
<dataset>
<log_info
id="9999"
batch_id="A0012345653"
type="1"
push_status="0"
error_log="2021-02-25 13:54:26"
/>
</dataset>
在preparedata目录建立如上的xml文件后,通过@DatabaseSetup引入:
@DatabaseSetup(value = {"classpath:preparedata/LogInfoMapper.xml"}, connection = "datasource", type = DatabaseOperation.INSERT)
@DatabaseTearDown
public class LogInfoMapperTest extends BaseTest {
经过如上配置,执行单测前会自动加载preparedata目录,来实现对一些特殊数据的初始化;
------------------------------------------------->>到底部了(⊙o⊙)…<<-----------------------------------------------