在我們使用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當中也是很大的工作量