在Spring中結合Dbunit對Dao進行整合單元測試
- package com.test.dbunit.dao;
- import javax.sql.DataSource;
- import org.dbunit.Assertion;
- import org.dbunit.database.DatabaseConnection;
- import org.dbunit.database.IDatabaseConnection;
- import org.dbunit.database.QueryDataSet;
- import org.dbunit.dataset.IDataSet;
-
import org.dbunit.dataset.xml.FlatXmlDataSet;
- import org.dbunit.operation.DatabaseOperation;
- import org.junit.Assert;
- import org.junit.Before;
- import org.junit.Test;
- import org.springframework.beans.factory.annotation.Autowired;
- import org.springframework.core.io.ClassPathResource;
-
import org.springframework.jdbc.datasource.DataSourceUtils;
- import org.springframework.test.context.ContextConfiguration;
- import org.springframework.test.context.junit4.AbstractTransactionalJUnit4SpringContextTests;
- import org.springframework.test.context.transaction.TransactionConfiguration;
- import com.test.dbunit.entity.User;
-
@ContextConfiguration
- @TransactionConfiguration(defaultRollback = true)
- publicclass UserDaoTest extends AbstractTransactionalJUnit4SpringContextTests {
- @Autowired
- private UserDao userDao;
- @Autowired
- private DataSource dataSource;
- private IDatabaseConnection conn;
- @Before
- publicvoid initDbunit() throws Exception {
- conn = new DatabaseConnection(DataSourceUtils.getConnection(dataSource));
- }
- @Test
- publicvoid saveUser() throws Exception {
- User user = new User();
- user.setNick("user001");
- user.setPassword("password001");
- userDao.save(user);
- QueryDataSet actual = new QueryDataSet(conn);
- actual.addTable("user",
- "select * from user where user.nick = 'user001'");
- IDataSet expected = new FlatXmlDataSet(new ClassPathResource(
- "com/taobao/dbunit/dao/user001.xml").getFile());
- Assertion.assertEquals(expected, actual);
- }
- @Test
- publicvoid updateUser() throws Exception {
- IDataSet origen = new FlatXmlDataSet(new ClassPathResource(
- "com/taobao/dbunit/dao/user001.xml").getFile());
- DatabaseOperation.INSERT.execute(conn, origen);
- User user = new User();
- user.setNick("user001");
- user.setPassword("password002");
- userDao.update(user);
- QueryDataSet actual = new QueryDataSet(conn);
- actual.addTable("user",
- "select * from user where user.nick = 'user001'");
- IDataSet expected = new FlatXmlDataSet(new ClassPathResource(
- "com/taobao/dbunit/dao/user001_updated.xml").getFile());
- Assertion.assertEquals(expected, actual);
- }
- @Test
- publicvoid removeUser() throws Exception {
- IDataSet origen = new FlatXmlDataSet(new ClassPathResource(
- "com/taobao/dbunit/dao/user001.xml").getFile());
- DatabaseOperation.INSERT.execute(conn, origen);
- userDao.remove("user001");
- QueryDataSet actual = new QueryDataSet(conn);
- actual.addTable("user", "select * from user where nick = 'user001'");
- Assert.assertEquals(0, actual.getTable("user").getRowCount());
- }
- @Test
- publicvoid findUser() throws Exception {
- IDataSet data = new FlatXmlDataSet(new ClassPathResource(
- "com/taobao/dbunit/dao/user001.xml").getFile());
- DatabaseOperation.INSERT.execute(conn, data);
- User user = userDao.getUserByNick("user001");
- Assert.assertEquals("password001", user.getPassword());
- }
- }
對Dao進行單元測試,一般有兩種思路。一是Mock,對使用的底層API進行Mock,比如Hibernate和JDBC介面,判斷介面有沒有正確呼叫,另一種是實際訪問資料庫,判斷資料庫有沒有正確讀寫。更多的情況下,我更傾向於後者,因為在使用ORM工具或者jdbcTemplate的情況下,dao一般只有簡單的幾行程式碼,沒有複雜的邏輯,Mock測試一般沒有什麼意義,我們更關心的是,Hibernate mapping是否正確,ibatis sql是否正確等,所以實際讀寫資料庫才能真正判斷一個dao是否正確,這也是我們關心的測試內容。
好的單元測試應該是原子性的,獨立的,不應依賴其他測試和上下文,但是要測試資料讀寫是否正確,就必須涉及初始資料的載入,資料修改的還原等操作。對於初始資料的載入,手動輸入很麻煩,一個解決方案就是使用Dbunit,從Xml檔案甚至Excel中載入初始資料到資料庫,是資料庫的值達到一個已知狀態。同時還可以使用Dbunit,對資料庫的結果狀態進行判斷,保證和期望的一致。資料修改的還原,可以依賴Spring TransactionalTests,在測試完成後回滾資料庫。
Dbunit還可以對資料的現有資料進行備份,還原,清空現有資料,一個好的測試實踐是每一個開發人員一個測試資料庫,進而對資料庫的資料狀態有更好的控制,但現實可能會是共享同一個測試庫,所以這種情況下,測試的編寫必須多做一些考慮。
待測試的類:
Java程式碼- package com.test.dbunit.dao.impl;
- import java.sql.ResultSet;
- import java.sql.SQLException;
- import org.springframework.jdbc.core.RowMapper;
- import com.test.dbunit.dao.UserDao;
- import com.test.dbunit.entity.User;
- publicclass DefaultUserDao extends BaseDao implements UserDao {
- privatestatic String QUERY_BY_NICK = "select * from user where user.nick = ?";
- privatestatic String REMOVE_USER = "delete from user where user.nick = ?";
- privatestatic String INSERT_USER = "insert into user(nick,password) values(?, ?)";
- privatestatic String UPDATE_USER = "update user set user.password = ? where user.nick = ?";
- @Override
- public User getUserByNick(String nick) {
- return (User) getJdbcTemplate().queryForObject(QUERY_BY_NICK,new Object[]{nick}, new RowMapper(){
- @Override
- public Object mapRow(ResultSet rs, int index) throws SQLException {
- User user = new User();
- user.setNick(rs.getString("nick"));
- user.setPassword(rs.getString("password"));
- return user;
- }
- });
- }
- @Override
- publicvoid remove(String nick) {
- getJdbcTemplate().update(REMOVE_USER, new Object[]{nick});
- }
- @Override
- publicvoid save(User user) {
- getJdbcTemplate().update(INSERT_USER, new Object[]{user.getNick(), user.getPassword()});
- }
- @Override
- publicvoid update(User user) {
- getJdbcTemplate().update(UPDATE_USER, new Object[]{user.getPassword(), user.getNick()});
- }
- }
單元測試:
需要注意的地方就是,DataSourceUtils.getConnection(datasource),通過這種方式獲得資料庫連線初始化Dbunit,能夠保證Dbunit使用的資料連線和當前事務的資料庫連線相同,保證能夠在參與到事務中。Spring的TransactionManager會在開始事務時把當前連線儲存到ThreadLocal中,DataSourceUtils.getConnection方法,首先從ThreadLocal中獲取連線。
user001.xml
Xml程式碼- <?xmlversion="1.0"encoding="UTF-8"?>
- <dataset>
- <usernick="user001"password="password001"/>
- </dataset>
使用dbunit,可以通過xml檔案定義資料集,也可以使用其他方式定義,比如Excel,程式設計方式。
Dbunit的主要構件
IDatabaseConnection
IDataSet
資料集,資料集可以從Xml檔案Excel等外部檔案獲取,也可以從資料庫查詢,或者程式設計方式構件,資料集可以作為初始資料插入到資料庫,也可以作為斷言的依據。另外還有IDatatable等輔助類。
比如在updateUser測試中,使用了QueryDataSet,從資料庫中構建一個Dataset,再通過FlatXmlDataSet從Xml檔案中構建一個Dataset,斷言這兩個Dataset相同。
Java程式碼- QueryDataSet actual = new QueryDataSet(conn);
- actual.addTable("user", "select * from user where user.nick = 'user001'");
- IDataSet expected = new FlatXmlDataSet(new ClassPathResource(
- "com/taobao/dbunit/dao/user001_updated.xml").getFile());
- Assertion.assertEquals(expected, actual);
DatabaseOperation
通過定義的靜態欄位可以獲取一組代表一個數據操作的子類物件,比如DatabaseOperation.INSERT,返回 InsertOperation,通過執行execute方法把資料集插入到資料庫。例如:
Java程式碼- IDataSet origen = new FlatXmlDataSet(new ClassPathResource(
- "com/taobao/dbunit/dao/user001.xml").getFile());
- DatabaseOperation.INSERT.execute(conn, origen);
從Xml檔案中構建DataSet,使用Insert插入到資料庫,初始化測試資料。
Assertion
唯一的方法,assertEqual,斷言兩個資料集或資料表相同。
PS:使用Oracle的時候,初始化DatabaseConnection需要傳入scheme。new DatabaseConnection(conn,SCHEMA_NAME) ,SCHMEA_NAME需要大寫。
附件提供所有程式碼下載
一個DAO測試基類
Java程式碼- package com.taobao.dbunit.dao;
- import java.sql.SQLException;
- import javax.sql.DataSource;
- import org.dbunit.Assertion;
-
相關推薦
在Spring中結合Dbunit對Dao進行整合單元測試
Java程式碼 package com.test.dbunit.dao; import javax.sql.DataSource; import org.dbunit.Assertion; import org.dbunit.
Spring對Controller、Service、Dao進行Junit單元測試總結
Spring對Controller、Service、Dao進行Junit單元測試總結 [email protected]事務控制,避免資料庫出現髒資料(若要提交到資料庫,先注掉) 2.hibernate配置檔案 <property name="defaultAutoComm
Spring Boot 2 實踐記錄之 使用 Powermock、Mockito 對 UUID 進行 mock 單元測試
alt 生成 digest md5 加密 調用 uuid tid 第一步 加密算 由於註冊時,需要對輸入的密碼進行加密,使用到了 UUID、sha1、md 等算法。在單元測試時,使用到了 Powermock,記錄如下。 先看下加密算法: import org.apache
springboot對shiro進行mock單元測試
環境:junit-5、Spring5.0.x、Spring Boot 2.0.x 以下是用來許可權測試的介面: @ApiOperation("[可接入]分頁查詢管理員") @ApiResponses({@ApiResponse(code
Spring整合Spring MVC及Mybatis進行Junit單元測試
我們可以在不啟動服務的情況下,進行單元測試,以便提交出高質量的程式碼。本文以一個小例子,說明在Spring中如何進行單元測試。 一:測試Controller 1:在pom.xml檔案中引入相關依賴 <properties> <!-- 設定專案編碼編碼 --&
在VS2017中使用Xlslib對Excel進行操作
/* 2018-10-12 16:57:05 使用xlslib來對Excel檔案的一些操作 VS2017編譯的一些問題 (這個庫只支援寫) */ 詳細的編譯過程見 參考:https://www.cnblogs.com/dongc/p/8256813.html
Python中使用numpy對序列進行離散傅立葉變換DFT
看了大佬對DFT的介紹後感覺離散傅立葉變換對序列訊號的處理還是很有用的, 總結下來就是DFT可以增加有限長序列的長度來提高物理解析度。 自己用python中的numpy庫實現了一下: 其中繪相簿的使用請參考:Python繪圖 將有效長度為4的單位序列,變換為長度16的DFT譜線。
Spring整合JUnit4進行AOP單元測試的時候,報:"C:\Program Files\Java\jdk1.8.0_191\bin\java.exe" -ea -Didea.test.cyclic.buffer.size=1048576 "-javaagent:C
錯誤程式碼 "C:\Program Files\Java\jdk1.8.0_191\bin\java.exe" -ea -Didea.test.cyclic.buffer.size=1048576 "-javaagent:C:\Program Files\JetBrains\IntelliJ IDEA
spring boot MongoTemplate如何 對 mongodb 進行模糊查詢
以下為部分程式碼片段,供參考。 1: 程式碼片段1,用Pattern方式來實現 不區分大小寫的匹配(包括精確和模糊匹配) //完全匹配 Pattern pattern = Pattern.compile("^張$", Pattern.CASE_INSENSITIVE);
在Spring中實現後臺對JSON傳的陣列物件給List型別的引數繫結
就是在後臺接收前端傳的JSON串,其中包含陣列型別的資料。例如傳一個user使用者列表,後臺用List來接收。 其實有多種方法都可以實現,大概就是JSON方式,和非JSON的key/value那種方法。但是後臺前輩告訴我,要考慮前臺不是所有都會這兩種傳參的方式,
在Node中基於Mongoose對MongoDB進行增刪查改(CRUD)操作(一)
關鍵詞:mongodb安裝 mongoose使用 robomongo mongoose的CRUD操作 mongoose的查詢,增加,修改,刪除 工具介紹 MongoDB MongoDB是基於Javascript語言的資料庫,儲存格式是JSON,而N
Java中Lamda表示式對List進行排序
public class MainTest { public static void main(String[] args) { List<String> list = Arrays.asList( "2018121207","2018121206","2018121
在entity framework 中使用 LINQ 對錶進行左關聯查詢且group by 分組查詢的示例,並且按小時分組查詢時間段
有表RealTimeDatas的欄位RecordTime儲存了實時時間,格式為DateTime 現在需要以小時進行分組統計每個時間段的最大值,最小值,和平均值 同時,另一個表Devices中有標準溫度溼度最大最小值範圍,需要將這個結果一併關聯到查詢結果中
Scikit-Learn(sklearn)中的KNeighborsClassifier對鳶尾花進行分類
案例 from sklearn import datasets from sklearn.model_selection import train_test_split from sklearn.neighbors import KNeighborsClassifier iris =
shell中date命令對month進行加減操作的bug
在大部分情況下這個命令執行正確。但是有些情況下這個命令會出現問題,比如當前日期是3月30、3月31、5月31等的時候,上面的命令得到的結果還是當月,而不是我們期望的上月。 這個問題是怎麼產生的呢?比如噹噹前日期是5月31時,-1 month它只是將月份-1,就得到4月31,但是實際上4月只有30天,所以
在storyboard或者xib中使用autolayout對UIScrollView進行佈局需要注意的問題
為了方便描述問題,我們從一個簡單的例子開始說起 首先在storyboard中拖入UIScrollView設定它的Leading Trailing Top 再給定一個高度height為200,再簡單不
MFC中利用ADO對資料庫進行簡單操作的例項
目標:實現對資料庫中的資料進行簡單地操作,包括增、刪、改、查。 第一步,建立一個基於對話方塊的應用程式,命名為TestAdo 第二步,按照圖1的介面佈局新增控制元件 圖1 程式介面示意圖 第三步,程式碼實現 首先,要用#import語句來引用支援ADO的
jmeter中利用BeanShell對時間進行復雜處理程式碼參考
1)生成格式化的時間,並設定生成的時間是在當前時間往後推幾天 import java.util.Date; import java.text.DateFormat; Date date=new Date();//取時間 Calendar calendar =
從資料庫中取出資料,存放到陣列中,然後對資料進行分類顯示
<table width="280" id="zhangdan_wenzi" > <?php //food_typ id 將id存到陣列中 $sqlfood = "SELECT food_type.id FROM food_type ";
利用Arrays類中的方法對陣列進行排序
package com.hongdou.java; import java.util.Arrays; public class MathDemo { public static void ma