在我们使用JUnit单元测试框架编写单元测试的时候,少不免要对数据库进行操作,但请试想一下,当我要编写一个获取用户的单元测试时,数据库是不存在该记录的,那么我要测试获取用户时就需要往数据库添加一条用户记录,但当获取用户的单元测试完成并成功后,此测试并没有清理现场(删除插入数据库的记录),那样当我们再有单元测试需要插入记录时,就会造成ID冲突的情况,少量的单元测试还可以避免此种情况,但当单元测试的数据庞大时,就会出现各种各样的问题,而DBUnit可以帮助我们解决这类型的问题
- <dependency>
- <groupId>org.dbunit</groupId>
- <artifactId>dbunit</artifactId>
- <version>2.4.9</version>
- <scope>test</scope>
- </dependency>
- <dependency>
- <groupId>org.slf4j</groupId>
- <artifactId>slf4j-api</artifactId>
- <version>1.7.5</version>
- <scope>compile</scope>
- </dependency>
在Maven管理的项目src/test/resource/下创建default-data.xml
- <?xml version="1.0" encoding="UTF-8"?>
- <dataset>
- <!-- 注意,此处的user代表表名(database table name) -->
- <user id="1" username="123" password="456"/>
- <user id="2" username="123" password="456"/>
- <user id="3" username="123" password="456"/>
- <user id="4" username="123" password="456"/>
- <user id="5" username="123" password="456"/>
- </dataset>
以下代码为提取后的BaseTest
- package com.accentrix.ray;
- import java.io.File;
- import java.io.FileInputStream;
- import java.io.FileWriter;
- import java.io.InputStream;
- import javax.sql.DataSource;
- import org.dbunit.database.DatabaseDataSourceConnection;
- import org.dbunit.database.IDatabaseConnection;
- import org.dbunit.database.QueryDataSet;
- import org.dbunit.dataset.DataSetException;
- import org.dbunit.dataset.IDataSet;
- import org.dbunit.dataset.xml.FlatXmlDataSet;
- import org.dbunit.dataset.xml.FlatXmlProducer;
- import org.dbunit.operation.DatabaseOperation;
- import org.junit.AfterClass;
- import org.junit.BeforeClass;
- import org.xml.sax.InputSource;
- public class BaseTest {
- public static IDatabaseConnection connection;
- public static DataSource dataSource;
- private File temp;
- @BeforeClass
- public static void init() throws Exception {
- // 通过DataSource获取DataBaseSourceConnection
- connection = new DatabaseDataSourceConnection(dataSource);
- }
- @AfterClass
- public static void destroy() throws Exception {
- if (connection != null) {
- connection.close();
- }
- }
- protected IDataSet getDataSet(String name) throws DataSetException {
- // 通过类加载器获取default-data.xml文件的内容
- InputStream is = this.getClass().getClassLoader()
- .getResourceAsStream(name + ".xml");
- // IDataSet就类似是一个数据的容器,把default-data.xml内容
- // 转换成了DBUnit可识别的数据返回出去
- return new FlatXmlDataSet(new FlatXmlProducer(new InputSource(is)));
- }
- protected void backupAll() throws Exception {
- // createDataSet代表从数据库中获取到DataSet,此时DataSet为数据库的内容
- IDataSet ds = connection.createDataSet();
- // 创建临时文件
- temp = File.createTempFile("temp", "xml");
- // 将数据库内容的DataSet写入临时文件当中
- FlatXmlDataSet.write(ds, new FileWriter(temp), "UTF-8");
- }
- protected void backupCustom(String... tableName) throws Exception {
- // 此种形式能保存某几张表的的数据,而不需要全部备份
- QueryDataSet qds = new QueryDataSet(connection);
- for (String str : tableName) {
- qds.addTable(str);
- }
- temp = File.createTempFile("temp", "xml");
- FlatXmlDataSet.write(qds, new FileWriter(temp), "UTF-8");
- }
- protected void recover() throws Exception {
- // 获取数据库内容的临时文件生成DataSet
- IDataSet ds = new FlatXmlDataSet(new FlatXmlProducer(new InputSource(
- new FileInputStream(temp))));
- // 使用DatabaseOperation的枚举方法先清空数据库内容再还原数据库
- DatabaseOperation.CLEAN_INSERT.execute(connection, ds);
- }
- }
以下为单元测试类
- package com.accentrix.ray;
- import static org.junit.Assert.assertEquals;
- import static org.junit.Assert.assertNotNull;
- import org.dbunit.dataset.IDataSet;
- import org.dbunit.operation.DatabaseOperation;
- import org.junit.Test;
- public class TestUser extends BaseTest {
- @Test
- public void testGetUser() throws Exception {
- // 首先获取到default-data.xml文件中的内容
- IDataSet ds = getDataSet("default-data.xml");
- // 调用backupAll方法保存数据库表
- backupAll();
- // 将default-data.xml中的内容替换成数据库的内容
- DatabaseOperation.CLEAN_INSERT.execute(connection, ds);
- // 进行单元测试逻辑的判断
- User user = userService.get(1);
- assertNotNull(user);
- assertEquals(user.getId(), new Integer(1));
- assertEquals(user.getPassword(), "456");
- assertEquals(user.getUsername(), "123");
- // 最后进行数据库的恢复
- // 当然我们也可以将backupAll和recover放在@Before和@After当中
- recover();
- }
- }
总结:
使用了DBUnit后可以实现了对数据库的隔离,成功弥补了JUnit单元测试不清理数据现场的缺憾,实际上DBUnit只是简单的在单元测试前把数据库的数据进行了备份然后插入xml中配置好的数据,在测试结束后再用备份好的原数据库数据填充回数据库.但当面对复杂的表关系和大数据量的时候,每次进行测试都进行数据的备份,也是一个很大的负担,而且把全部的测试数据都编写在xml当中也是很大的工作量