Springboot+DBunit单元测试,数据库隔离测试

关于DBunit

百度百科:dbunit是一个基于junit扩展的数据库测试框架。
简言之,dbunit是为了在单元测试中,通过备份数据库、导入测试数据、回滚恢复数据库的手段,在不污染数据库的前提下完成一系列单元测试工作。

DBunit关键知识点

IDataSet接口:用于操作表集合
ITable接口:用于操作表数据集合
DatabaseOperation类:对表数据执行一系列操作,比如刷新、删除、插入等

DBunit操作流程

在没使用DBunit做单元测试之前,一般遵循junit的测试流程:

  1. @BeforeClass在加载测试类之前执行初始化操作
  2. @Before执行单元测试方法前执行操作
  3. @Test执行测试逻辑
  4. @After执行单元测试方法后执行操作
  5. @AfterClass在测试类结束后操作

加入DBunit实际上只是在junit的流程中添加几步操作数据库的动作:

  1. @BeforeClass构建连接数据源(DataSource)
  2. @Before创建连接,备份数据并且插入测试数据
  3. @Test执行测试逻辑
  4. @After测试完成还原数据
  5. @AfterClass关闭连接

操作的流程不是固定的,具体还是要根据测试的逻辑来决定,如果能够加入事务特性进行单元测试可以大大精简流程

Springboot集成DBunit步骤

进入正题,这里使用的版本是:

  • DBunit 2.5.3
  • Springboot 2

一、引用依赖


		
		<dependency>
			<groupId>org.springframework.bootgroupId>
			<artifactId>spring-boot-starter-testartifactId>
			<scope>testscope>
		dependency>

		
		<dependency>
			<groupId>org.dbunitgroupId>
			<artifactId>dbunitartifactId>
			<version>2.5.3version>
			<scope>testscope>
		dependency>

二、初始化表&创建测试数据

初始化SQL脚本:

CREATE TABLE `db_unit_test` (
  `id` bigint(20) NOT NULL,
  `name` varchar(255) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

测试数据XML:


<dataset>
    <db_unit_test id="1" name="张三"/>
    <db_unit_test id="2" name="李四"/>
    <db_unit_test id="3" name="王五"/>
dataset>

三、封装DBunit方法

AbstractBaseTest封装DBunit基本操作方法,包含初始化连接、关闭连接方法,备份数据、还原数据、导入数据和清空数据方法。其中AbstractBaseTest继承了AbstractTransactionalJUnit4SpringContextTests类的事务特性,可以方便使用事务回滚特性实现数据库0污染。
参考:https://www.cnblogs.com/wade-xu/p/4547381.html

/**
 *  
 * 单元测试基类
 * 封装DBunit相关操作方法
 * 
* https://www.cnblogs.com/wade-xu/p/4547381.html * @author oyf */
@RunWith(SpringJUnit4ClassRunner.class) @Transactional //继承AbstractTransactionalJUnit4SpringContextTests会在方法执行完成后进行事务回滚,如果需要不回滚事务需要在方法上加上 @Rollbak(false) public abstract class AbstractBaseTest extends AbstractTransactionalJUnit4SpringContextTests { @Autowired private DataSource dataSource; /** * 数据库连接对象 */ private static IDatabaseConnection conn; /** * 备份文件 */ private File tempFile; /** * 文件跟目录 */ public static final String ROOT_URL = "src/test/resources/"; // DBunit方法 -------------------------------------------------------- /** * 获取数据库连接 * @throws Exception */ @Before public void setup() throws Exception { //get DataBaseSourceConnection conn = new DatabaseConnection(DataSourceUtils.getConnection(dataSource)); } /** * 关闭数据库连接 * @throws Exception */ //这里不能用@After,当测试方法有@Rollback(false)注解时会在事务没有结束之前关闭了数据库连接 @AfterTransaction public void teardown() throws Exception { if (conn != null) { conn.close(); } } /** * Get Query DataSet * * @Title: getQueryDataSet * @return * @throws SQLException */ protected QueryDataSet getQueryDataSet() throws SQLException { return new QueryDataSet(conn); } /** * 备份表数据 * * @Title: backupCustom * @param tableName * @throws Exception */ protected void backupCustom(String... tableName){ try { // back up specific files QueryDataSet qds = getQueryDataSet(); for (String str : tableName) { qds.addTable(str); } tempFile = new File(ROOT_URL+"temp.xml"); FlatXmlDataSet.write(qds, new FileWriter(tempFile), "UTF-8"); } catch (Exception e) { e.printStackTrace(); } } /** * 清空表数据,并导入测试数据 * @throws Exception */ public void importTables(String file){ try { IDataSet dataSet = new FlatXmlDataSetBuilder().build(new File(ROOT_URL+file)); DatabaseOperation.CLEAN_INSERT.execute(conn, dataSet); } catch (Exception e) { e.printStackTrace(); } } /** * 回滚数据 * * @Title: rollback * @throws Exception */ protected void rollback(){ try { // get the temp file FlatXmlDataSetBuilder builder = new FlatXmlDataSetBuilder(); builder.setColumnSensing(true); IDataSet ds =builder.build(new FileInputStream(tempFile)); // recover database DatabaseOperation.CLEAN_INSERT.execute(conn, ds); } catch (Exception e) { e.printStackTrace(); } } /** * 清空表数据 * * @param tableName * @throws Exception */ protected void clearTable(String tableName){ try { DefaultDataSet dataset = new DefaultDataSet(); dataset.addTable(new DefaultTable(tableName)); DatabaseOperation.DELETE_ALL.execute(conn, dataset); }catch (Exception e) { e.printStackTrace(); } } }

四、准备业务代码

主要是准备查询数据用的service和dao,具体代码可以在https://gitee.com/oumuv/h2TestDemo下载
Springboot+DBunit单元测试,数据库隔离测试_第1张图片

五、编写测试类

这里简单演示了两种方式实现数据库隔离测试,test1()方法用spring的事务特性,test2()使用DBunit手动回滚数据

/**
 * 测试demo
 */
@RunWith(SpringJUnit4ClassRunner.class)
@SpringBootTest(classes = H2Application.class)
public class TestDemo2 extends AbstractBaseTest{

    @Autowired
    DBunitService dBunitService;

    /**
     * 使用事务回滚机制,自动还原数据库
     */
    @Test
    public void test1() {
        //导入测试数据
        importTables("dbunit-data.xml");
        List<DBunitEntity> list = dBunitService.list();
        Assert.assertNotNull(list);
    }

    /**
     * 加上注解 @Rollback(false) 不使用事务回滚,手动还原数据库
     */
    @Test
    @Rollback(false)
    public void test2() {
        //备份数据,备份数据在resources/temp.xml
        backupCustom("db_unit_test");
        //导入测试数据
        importTables("dbunit-data.xml");
        List<DBunitEntity> list = dBunitService.list();
        Assert.assertNotNull(list);
        //手动恢复数据
        rollback();
    }
}

运行测试用例发现查出来的数据确实是xml中的测试数据,而数据库中的数据并没有被污染也没有缺失,结果便是成功了!

具体代码可在https://gitee.com/oumuv/h2TestDemo自行下载

你可能感兴趣的:(Spring,Java,Junit)