之前记录了使用flyway管理数据库的初始化,flyway也可以进行数据初始化,不过是直接使用sql语句,dbunit可以使用xml文件对数据库里面的数据进行管理,而且对于数据的管理更为灵活,下面就简单介绍一下如何使用spring-test-dbunit。
添加gradle依赖
testCompile group: 'org.dbunit', name: 'dbunit', version: '2.6.0'
testCompile group: 'com.github.springtestdbunit', name: 'spring-test-dbunit', version: '1.3.0'
在类中使用
首先在测试类上面加注解@TestExecutionListeners,把常用的listener都添加进去
在想要使用dbunit做数据初始化和恢复的方法上面加注解@DatabaseSetup,@DatabaseTearDown
方法开始前将使用DatabaseSetup中指定的文件对数据库中的数据进行初始化,方法结束之后将使用DatabaseTearDown指定的文件恢复数据库的数据。其中,type指定数据库的操作类型,我这里随便指定了一下。
@WebAppConfiguration
@SpringBootTest
@ContextConfiguration(classes = { Application.class })
@AutoConfigureMockMvc
@TestExecutionListeners({
DependencyInjectionTestExecutionListener.class,
DirtiesContextTestExecutionListener.class,
TransactionalTestExecutionListener.class,
DbUnitTestExecutionListener.class
})
public class SpringBootTestBaseClass {
@Test
@DisplayName("test for spring-test-dbunit")
@DatabaseSetup(type = DatabaseOperation.INSERT, value = "classpath:dbunit/test.xml")
@DatabaseTearDown(type = DatabaseOperation.DELETE, value = "classpath:dbunit/test.xml")
public void springTestDbunit() {
//todo sth.
}
}
数据库的操作类型如下:
public enum DatabaseOperation {
/**
* Updates the contents of existing database tables from the dataset.
*/
UPDATE,
/**
* Inserts new database tables and contents from the dataset.
*/
INSERT,
/**
* Refresh the contents of existing database tables. Rows from the dataset will insert or replace existing data. Any
* database rows that are not in the dataset remain unaffected.
*/
REFRESH,
/**
* Deletes database table rows that matches rows from the dataset.
*/
DELETE,
/**
* Deletes all rows from a database table when the table is specified in the dataset. Tables in the database but not
* in the dataset remain unaffected.
* @see #TRUNCATE_TABLE
*/
DELETE_ALL,
/**
* Deletes all rows from a database table when the table is specified in the dataset. Tables in the database but not
* in the dataset are unaffected. Identical to {@link #DELETE_ALL} expect this operation cannot be rolled back and
* is supported by less database vendors.
* @see #DELETE_ALL
*/
TRUNCATE_TABLE,
/**
* Deletes all rows from a database table when the tables is specified in the dataset and subsequently insert new
* contents. Equivalent to calling {@link #DELETE_ALL} followed by {@link #INSERT}.
*/
CLEAN_INSERT;
}
spring-test-dbunit提供了使用注解来对数据进行操作的方法,但是,如果我们在测试开始之前想要对整个数据库进行备份,测试之后再恢复原先数据的话,我并没有找到可以用的注解,为了实现这个需求,可以直接使用dbunit进行实现。
@WebAppConfiguration
@SpringBootTest
@ContextConfiguration(classes = { Application.class })
@AutoConfigureMockMvc
@TestExecutionListeners({
DependencyInjectionTestExecutionListener.class,
DirtiesContextTestExecutionListener.class,
TransactionalTestExecutionListener.class,
DbUnitTestExecutionListener.class
})
public class SpringBootTestBaseClass {
@Resource
protected DataSource dataSource;
protected IDatabaseConnection connection;
String backupFile = "dbunit/backup.xml";
@BeforeEach
public void init() throws Exception {
DatabaseDataSourceConnectionFactoryBean factoryBean = dbUnitDatabaseConnection();
connection = factoryBean.getObject();
}
/*
这个方法主要是对dbunit进行配置,其中setDatatypeFactory的设置表示我们的测试数据库是h2数据库,
setEscapePattern的设置给每个字段的前后各提供了一个`,主要是为了防止表里有特殊字段
(比如字段名为order)导致的sql语句错误,setAllowEmptyFields的设置表示允许空的字段。
*/
private DatabaseDataSourceConnectionFactoryBean dbUnitDatabaseConnection() {
DatabaseConfigBean bean = new DatabaseConfigBean();
bean.setDatatypeFactory(new H2DataTypeFactory());
bean.setEscapePattern("`");
bean.setAllowEmptyFields(true);
DatabaseDataSourceConnectionFactoryBean dbConnectionFactory =
new DatabaseDataSourceConnectionFactoryBean(dataSource);
dbConnectionFactory.setDatabaseConfig(bean);
return dbConnectionFactory;
}
/*
备份指定的表格
*/
public void backup(List<String> tables) throws Exception {
QueryDataSet dataSet = new QueryDataSet(connection);
for (String t : tables) {
dataSet.addTable(t);
}
FlatXmlDataSet.write(dataSet, getBackupFile());
}
/*
备份所有的表格,其中filter表示备份的时候忽略掉名为FLYWAY_SCHEMA_HISTORY的表格
(这个是之前使用flyway自动创建的表格)
*/
public void backup() throws Exception {
ITableFilter filter = new ExcludeTableFilter(new String[] { "FLYWAY_SCHEMA_HISTORY" });
IDataSet dataSet = new FilteredDataSet(filter, connection.createDataSet());
FlatXmlDataSet.write(dataSet, getBackupFile());
}
/*
恢复数据库信息
CLEAN_INSERT表示删除旧的并插入新的数据
*/
public void recover() throws Exception {
IDataSet ds = getiDataSet(backupFile);
DatabaseOperation.CLEAN_INSERT.execute(connection, ds);
}
private IDataSet getiDataSet(String fileName) throws Exception {
FlatXmlDataSetBuilder builder = new FlatXmlDataSetBuilder();
builder.setColumnSensing(true);
return builder.build(Resources.getResource(fileName));
}
/*
我的backup的文件放在resources下面的dbunit文件夹下面,这个方法是为了拿到backup文件,
使用之前要先创建它,其实backup文件可以直接使用相对的文件名称backup.xml,不放在resources下面
*/
private FileOutputStream getBackupFile() throws FileNotFoundException, URISyntaxException {
String path = Resources.getResource(backupFile).toURI().getPath();
return new FileOutputStream(path);
}
}
下面是xml文件的格式,service里面定义的是表service的数据,user表是空的,backup整个数据库的时候,就显示<user/>
<?xml version='1.0' encoding='UTF-8'?>
<dataset>
<service id="1" name="Test" description="test"/>
<service id="2" name="Preference" description="preference"/>
<user/>
</dataset>