1、DbUnit設計理念
熟悉單元測試的開發人員都知道,在對數據庫進行單元測試時候,一般採用的方案有運用模擬對象(mock objects)和stubs兩種。經過隔離關聯的數據庫訪問類,好比JDBC的相關操做類,來達到對數據庫操做的模擬測試。然而某些特殊的系統,好比利 用了EJB的CMP(container-managed persistence)的系統,數據庫的訪問對象是在最底層並且很隱蔽的,那麼這兩種解決方案對這些系統就顯得力不從心了。
DBUnit的設計理念就是在測試以前,備份數據庫,而後給對象數據庫植入咱們須要的準備數據,最後,在測試完畢後,讀入備份數據庫,回溯到測試前的狀態;並且又由於DBUnit是對JUnit的一種擴展,開發人員能夠經過建立測試用例代碼,在這些測試用例的生命週期內來對數據庫的操做結果進行比較。java
2、DbUnit測試基本概念和流程
基於DbUnit 的測試的主要接口是IDataSet。IDataSet表明一個或多個表的數據。
能夠將數據庫模式的所有內容表示爲單個IDataSet 實例。這些表自己由Itable 實例來表示。
IDataSet 的實現有不少,每個都對應一個不一樣的數據源或加載機制。最經常使用的幾種 IDataSet實現爲:mysql
FlatXmlDataSet:數據的簡單平面文件 XML 表示
QueryDataSet:用 SQL 查詢得到的數據
DatabaseDataSet:數據庫表自己內容的一種表示
XlsDataSet :數據的excel表示
DBUnit支持的數據庫包括,db2,h2,hsqldb,mckoi,mssql,mysql,netezza,oralce,postgresql.sql
3、DBUnit測試流程:數據庫
通常而言,使用DbUnit進行單元測試的流程以下: 1 根據業務,作好測試用的準備數據和預想結果數據,一般準備成xml格式文件。 2 在setUp()方法裏邊備份數據庫中的關聯表。 3 在setUp()方法裏邊讀入準備數據。 4 對測試類的對應測試方法進行實裝:執行對象方法,把數據庫的實際執行結果和預想結果進行比較。 5 在tearDown()方法裏邊,把數據庫還原到測試前狀態。
4、實例開發:ide
一、新建一個pom工程,加入相關依賴:post
<dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.11</version> <scope>test</scope> </dependency> <dependency> <groupId>org.dbunit</groupId> <artifactId>dbunit</artifactId> <version>2.5.3</version> </dependency> <dependency> <groupId>org.slf4j</groupId> <artifactId>slf4j-nop</artifactId> <version>1.7.24</version> </dependency> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>5.1.38</version> </dependency>
二、新建工程相關目錄單元測試
BaseDao.java文件:測試
public class BaseDao { private static Connection CONNECTION_INSTANCE = null; protected Connection getConnection() throws Exception{ if(null==CONNECTION_INSTANCE){ Class.forName("com.mysql.jdbc.Driver"); CONNECTION_INSTANCE=DriverManager.getConnection("jdbc:mysql://127.0.0.1:3306/test","root","root"); } return CONNECTION_INSTANCE; } protected void closeConnection() throws Exception{ if(null!=CONNECTION_INSTANCE){ if(!CONNECTION_INSTANCE.isClosed()){ CONNECTION_INSTANCE.close(); } CONNECTION_INSTANCE=null; } } }
DBUnitUtils.java文件大數據
public class DBUnitUtils { //產生數據集 public static void generateDatasetDtd(String[] tables) throws Exception{ QueryDataSet dataSet=new QueryDataSet(DButils.getDataBaseConnection()); for(String _table:tables){ dataSet.addTable(_table); } FlatDtdDataSet.write(dataSet, new FileOutputStream(new File("resource/tmp.dtd"))); //FlatXmlDataSet.write(dataSet,new FileOutputStream(new File("resource/dbunit1.xml"))); } //備份表數據 public static void backupDatabase(String[] tables,File backupFile) throws Exception{ QueryDataSet dataSet=new QueryDataSet(DButils.getDataBaseConnection()); for(String _table:tables){ dataSet.addTable(_table); } FlatXmlDataSet.write(dataSet, new FileOutputStream(backupFile)); } //清空表數據,並導入測試數據 public static void importTables(File dataFile) throws Exception{ IDataSet dataSet=new FlatXmlDataSetBuilder().build(dataFile); DatabaseOperation.CLEAN_INSERT.execute(DButils.getDataBaseConnection(), dataSet); } //清空表數據,恢復備份數據 public static void resumeDatabase(File backupFile) throws Exception{ IDataSet dataSet=new FlatXmlDataSetBuilder().build(backupFile); DatabaseOperation.CLEAN_INSERT.execute(DButils.getDataBaseConnection(), dataSet); } }
DButils.java文件ui
public class DButils { private static IDatabaseConnection conn; //經過dbUnit建立數據庫鏈接 public static IDatabaseConnection getDataBaseConnection() throws ClassNotFoundException, SQLException, DatabaseUnitException{ if(conn==null){ Class.forName("com.mysql.jdbc.Driver"); Connection dbConn=DriverManager.getConnection("jdbc:mysql://localhost:3306/test", "root", "root"); conn =new MySqlConnection(dbConn,"test"); return conn; } return conn; } //關閉數據庫鏈接 public static void closeConnection(){ if(conn!=null){ try { conn.close(); } catch (SQLException e) { e.printStackTrace(); } } conn=null; } }
User.java文件
public class User { private long id; private String username; private String password; private String name; public long getId() { return id; } public void setId(long id) { this.id = id; } public String getUsername() { return username; } public void setUsername(String username) { this.username = username; } public String getPassword() { return password; } public void setPassword(String password) { this.password = password; } public String getName() { return name; } public void setName(String name) { this.name = name; } }
UserService.java文件
public interface UserService { public long create(User user) throws Exception; public void update(User user) throws Exception; public User get(Long id) throws Exception; public void delete(Long id) throws Exception; public List<User> list() throws Exception; }
UserServiceImpl.java文件
public class UserServiceImpl extends BaseDao implements UserService{ //新增用戶返回主鍵 public long create(User user) throws Exception { Long id=null; PreparedStatement stm=getConnection().prepareStatement("insert into user(username, password, name) values(?, ?, ?)", Statement.RETURN_GENERATED_KEYS); stm.setString(1, user.getName()); stm.setString(2, user.getPassword()); stm.setString(3, user.getName()); stm.executeUpdate(); ResultSet rs=stm.getGeneratedKeys(); if(rs.first()){ id=rs.getLong(1); } return id; } //更新用戶 public void update(User user) throws Exception { PreparedStatement stm = getConnection().prepareStatement("update user set password = ?, name = ? where username = ?", Statement.RETURN_GENERATED_KEYS); stm.setString(1, user.getPassword()); stm.setString(2, user.getName()); stm.setString(3, user.getUsername()); stm.executeUpdate(); closeConnection(); } //獲取用戶 public User get(Long id) throws Exception { User user = null; PreparedStatement stm = getConnection().prepareStatement("select username, password, name from user where id=?"); stm.setLong(1, id); ResultSet rs = stm.executeQuery(); if (rs.first()) { user = new User(); user.setUsername(rs.getString(1)); user.setPassword(rs.getString(2)); user.setName(rs.getString(3)); user.setId(id); } closeConnection(); return user; } //刪除用戶 public void delete(Long id) throws Exception { PreparedStatement stm = getConnection().prepareStatement("delete from user where id=?"); stm.setLong(1, id); stm.executeUpdate(); closeConnection(); } //返回全部用戶列表 public List<User> list() throws Exception { List<User> users = new ArrayList<User>(); PreparedStatement stm = getConnection().prepareStatement("select username, password, name, id from user"); ResultSet rs = stm.executeQuery(); while (rs.next()) { User user = new User(); user.setUsername(rs.getString(1)); user.setPassword(rs.getString(2)); user.setName(rs.getString(3)); user.setId(rs.getLong(4)); users.add(user); } closeConnection(); return users; } }
UserServiceDBTestCase.java文件
public class UserServiceDBTestCase extends DatabaseTestCase{ private UserService userService; @Override //新建一個userDao對象 protected void setUp() throws Exception { super.setUp(); userService = new UserServiceImpl(); } @Override //清空userDao對象 protected void tearDown() throws Exception { super.tearDown(); userService = null; } @Override //獲取數據庫鏈接 protected IDatabaseConnection getConnection() throws Exception { Class.forName("com.mysql.jdbc.Driver"); Connection conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/test", "root", "root"); return new MySqlConnection(conn, "test"); } //獲取輸入數據流 @Override protected IDataSet getDataSet() throws Exception { InputStream is = getClass().getResourceAsStream("/test-data.xml"); return new FlatXmlDataSetBuilder().build(is); } //測試數據的建立 public void testCreate() throws Exception{ User user = new User(); user.setName("testdata"); user.setPassword("testPassword"); user.setUsername("testAdmin"); Long id = userService.create(user); assertNotNull(id); User dbUser =userService.get(id); assertNotNull(dbUser); assertEquals("testAdmin", dbUser.getUsername()); assertEquals("testPassword", dbUser.getPassword()); assertEquals("testAdministrator", dbUser.getName()); } public void testGet() throws Exception{ User user = userService.get(1L); assertNotNull(user); assertEquals("admin1", user.getUsername()); assertEquals("123", user.getPassword()); assertEquals("Administrator1", user.getName()); User nullUser = userService.get(0L); assertNull(nullUser); } public void testDelete() throws Exception{ User user = userService.get(1L); assertNotNull(user); userService.delete(1L); User nullUser = userService.get(1L); assertNull(nullUser); } public void testList() throws Exception{ List<User> users = userService.list(); assertNotNull(users); assertEquals(4, users.size()); } }
UserServiceTestCase.java文件
public class UserServiceTestCase extends TestCase{ private UserService userService; private File backupFile=new File("resource/backup-data.xml"); @Override protected void setUp() throws Exception { userService=new UserServiceImpl(); } @Before public void setUpData() throws Exception { //備份原來的數據 DBUnitUtils.backupDatabase(new String []{"user"}, backupFile); //導入測試數據 DBUnitUtils.importTables(new File("resource/test-data.xml")); } @After public void tearDownData() throws Exception{ //恢復備份數據 DBUnitUtils.resumeDatabase(backupFile); //關閉數據庫鏈接 DButils.closeConnection(); } public void testCreate() throws Exception{ DBUnitUtils.importTables(new File("resource/test-data.xml")); User user = new User(); DBUnitUtils.resumeDatabase(backupFile); DButils.closeConnection(); user.setName("testdata"); user.setPassword("testPassword"); user.setUsername("testAdmin"); Long id = userService.create(user); assertNotNull(id); User dbUser =userService.get(id); assertNotNull(dbUser); assertEquals("testAdmin", dbUser.getUsername()); assertEquals("testPassword", dbUser.getPassword()); assertEquals("testAdministrator", dbUser.getName()); } public void testGet() throws Exception{ User user = userService.get(1L); assertNotNull(user); assertEquals("admin1", user.getUsername()); assertEquals("123", user.getPassword()); assertEquals("Administrator1", user.getName()); User nullUser = userService.get(0L); assertNull(nullUser); } public void testDelete() throws Exception{ User user = userService.get(1L); assertNotNull(user); userService.delete(1L); User nullUser = userService.get(1L); assertNull(nullUser); } public void testList() throws Exception{ List<User> users = userService.list(); assertNotNull(users); assertEquals(4, users.size()); } }
test-data.xml文件
<?xml version='1.0' encoding='UTF-8'?> <dataset> <user id="1" username="test-user1" password="test-user1" name="test-user1"/> <user id="2" username="test-user2" password="test-user2" name="test-user2"/> </dataset>
接下來測試結果:
demo代碼下載: dbunitDemo
總結:
使用了DBUnit後能夠實現了對數據庫的隔離,成功彌補了JUnit單元測試不清理數據現場的缺憾,實際上DBUnit只是簡單的在單元測試前把數據庫的數據進行了備份而後插入xml中配置好的數據,在測試結束後再用備份好的原數據庫數據填充回數據庫.但當面對複雜的表關係和大數據量的時候,每次進行測試都進行數據的備份,也是一個很大的負擔,並且把所有的測試數據都編寫在xml當中也是很大的工做量