轉載自 積木
http://jim19770812.blogspot.com/2009/12/dbunit.html
DBUnit是基於JUnit的擴展,提供了基於數據庫的測試數據的自動化測試,並且DBUnit提供了強大的導入導出數據功能,可以很容易的構造乾淨的數據測試環境。
除了使用DBUnit實現自動化的數據單元測試,還可以用來實現類似數據庫備份/恢復的功能,道理都是差不多的。
網上常見的幾個關於DBUnit的問題
1.因爲外鍵約束造成導入失敗
其實DBUnit是可以避免這個問題的,關鍵在於不要使用FlatXmlDataSet,改用CsvDataSetWriter就不會有外鍵問題了。
2.自己實現了基於SQL腳本的數據測試工具
我認爲這種做法不可取,首先是測試數據的準備時間太長,數據量較少的話還可以用用,如果數據量比較大,寫sql還不得累死?要是表結構再有了變化所有sql又得重新修改一遍。使用DBUnit就簡單多了,數據庫變了只要把新數據庫重新導出一遍就可以了,非常容易。
代碼如下:
package com.dbdata; import java.io.File; import java.sql.Connection; import java.sql.SQLException; import java.util.List; import javax.swing.JFileChooser; import org.dbunit.DatabaseUnitException; import org.dbunit.database.DatabaseConnection; import org.dbunit.database.IDatabaseConnection; import org.dbunit.database.QueryDataSet; import org.dbunit.dataset.IDataSet; import org.dbunit.dataset.csv.CsvDataSet; import org.dbunit.dataset.csv.CsvDataSetWriter; import org.dbunit.operation.DatabaseOperation; import com.gdw.common.util.FileUtil; public class DBDataUtil { private IDatabaseConnection connection =null; /** * 打開連接,相當於JDBC的DriverManager.getConnection() * @param conn * @return */ public boolean open(final Connection conn){ try { this.connection = new DatabaseConnection(conn); return connection != null; } catch (DatabaseUnitException e) { e.printStackTrace(); return false; } } /** * 關閉連接,相當於JDBC的connection.close; * @return */ public boolean close(){ if (this.connection != null){ try { this.connection.close(); return true; } catch (SQLException e) { e.printStackTrace(); } return false; } return true; } /** * 導出數據到指定的目錄下 * @param tableNames 表名列表,注意外鍵關係,要按照順序排列(先導出字典,再導出主表) * @param destFolder 導出目錄 * @return */ public boolean exp(final List tableNames, final File destFolder){ QueryDataSet dataSet = new QueryDataSet(connection); try{ for(String tableName : tableNames){ dataSet.addTable(tableName); } CsvDataSetWriter.write(dataSet, destFolder); this.saveDefaultPath(destFolder.getParent()); return true; }catch(Exception e){ e.printStackTrace(); } return false; } /** * 導入數據,會根據導出時的順序依次導入,如果出現了因外鍵約束而導入失敗的情況,請調整導出時的表順序 * @param sourceFolder * @return */ public boolean imp(final File sourceFolder){ try{ IDataSet dataSet = new CsvDataSet(sourceFolder); //準備讀入數據 DatabaseOperation.CLEAN_INSERT.execute(connection, dataSet); return true; }catch(Exception e){ e.printStackTrace(); } return false; } /** * 選擇打開目錄 * @return */ public static String showOpenFolder(){ String defaultPath = loadDefaultPath(); JFileChooser jf = new JFileChooser(defaultPath); jf.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY); int ret = jf.showOpenDialog(null); if (ret != JFileChooser.APPROVE_OPTION){ return null; } return jf.getSelectedFile().getAbsolutePath(); } /** * 選擇保存目錄 * @param defaultPath 默認目錄 * @return */ public static String showSaveFolder(){ String defaultPath = loadDefaultPath(); JFileChooser jf = new JFileChooser(defaultPath); jf.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY); int ret = jf.showSaveDialog(null); if (ret != JFileChooser.APPROVE_OPTION){ return null; } return jf.getSelectedFile().getAbsolutePath(); } public static String loadDefaultPath(){ File f = new File(".lastpath"); System.out.println(f.getAbsolutePath()); if (f.isFile() && f.exists()){ return FileUtil.readAbsolutFile(f.getAbsolutePath()); } return null; } public static void saveDefaultPath(final String defaultPath){ File f = new File(".lastpath"); FileUtil.writeFile(".lastpath", defaultPath); System.out.println(f.getAbsolutePath()); } }
導出代碼
package com.dbdata; import java.io.File; import java.sql.Connection; import java.sql.DriverManager; import java.util.ResourceBundle; import com.gdw.common.util.StringUtil; public class DataImporter { public boolean imp(final String jdbcClassName, final String url, final String userName, final String password, final String folder){ try{ Class.forName(jdbcClassName); Connection conn = DriverManager.getConnection(url, userName, password); DBDataUtil util = new DBDataUtil(); util.open(conn); try{ boolean ret = util.imp(new File(folder)); return ret; }finally{ util.close(); } }catch(Exception e){ e.printStackTrace(); } return false; } public static void main(String[] args) { Connection conn = null; try{ String folder = DBDataUtil.showOpenFolder(); if (StringUtil.isNull(folder)){ return; } ResourceBundle rs = ResourceBundle.getBundle("_dbutil"); boolean ret = new DataImporter().imp(rs.getString("db.classname"), rs.getString("db.url"), rs.getString("db.username"), rs.getString("db.password"), folder); System.out.println(ret ? "導入成功!" : "導入失敗"); }catch(Exception e){ e.printStackTrace(); } } }
導入代碼
package com.dbdata; import java.io.File; import java.sql.Connection; import java.sql.DriverManager; import java.util.LinkedList; import java.util.List; import java.util.ResourceBundle; import com.gdw.common.util.StringUtil; public class DataExporter { public boolean exp(final String jdbcClassName, final String url, final String userName, final String password, final List tableNames, final String folder){ try{ Class.forName(jdbcClassName); Connection conn = DriverManager.getConnection(url, userName, password); DBDataUtil util = new DBDataUtil(); util.open(conn); try{ boolean ret = util.exp(tableNames, new File(folder)); return ret; //System.out.println(ret ? "導出成功!" : "導出失敗"); }finally{ util.close(); } }catch(Exception e){ e.printStackTrace(); } return false; } public static void main(String[] args) { Connection conn = null; try{ ResourceBundle rs = ResourceBundle.getBundle("_dbutil"); List tableNames = new LinkedList(); tableNames.add("muser"); tableNames.add("mmenu"); tableNames.add("mtable1"); tableNames.add("mtable2"); tableNames.add("mtable3"); tableNames.add("mtable4"); tableNames.add("mtable5"); tableNames.add("mtable6"); tableNames.add("mtable7"); String folder = DBDataUtil.showSaveFolder(); if (StringUtil.isNull(folder)){ return; } boolean ret = new DataExporter().exp(rs.getString("db.classname"), rs.getString("db.url"), rs.getString("db.username"), rs.getString("db.password"), tableNames, folder); System.out.println(ret ? "導出成功!" : "導出失敗"); }catch(Exception e){ e.printStackTrace(); } } }
_dbutil.properties 內容如下
db.classname=com.mysql.jdbc.Driver db.url=jdbc:mysql://localhost:3306/mydb?useUnicode=true&characterEncoding=UTF-8 db.username=root db.password=jim
用DBUnit實現數據測試的用法
1.在數據庫中生成測試數據
2.用DataExporter導出測試數據
2.編寫單元測試
2.1.測試執行前使用DataExporter把業務表備份到臨時目錄
2.2.使用DataImporter導入測試數據
2.3.執行單元測試
2.4.使用DataImporter將先前做的備份數據恢復
經過本人測試,以上代碼可以在包含外鍵約束的mysql數據庫環境下運行正常。
如果你有興趣的話,還可以在此基礎上改成基於命令行或者圖形化界面的工具,這樣用起來更容易。