使用Mock進行業(yè)務(wù)邏輯層Service測試詳解
場景
公司采用的是分層開發(fā),controller、Service、dao層分離,現(xiàn)在寫dao層代碼的人生病了,進度比較慢,現(xiàn)在你寫的是 Service層的代碼,怎么測試 Service 層代碼是否正確呢?
Service層測試的重點是什么?
- DAO層調(diào)用的次數(shù)
- 以及調(diào)用的順序
- 并不關(guān)心最后數(shù)據(jù)是否準(zhǔn)確
mock是什么?
在軟件測試中,mock是一種模擬對象的技術(shù),用于在測試過程中替代真實的對象。
通過mock,我們可以控制被模擬對象的行為和返回值,以便進行更加精確的測試。
測試代碼示例
準(zhǔn)備環(huán)境
引入依賴
<!-- Junit測試包 --> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.13</version> </dependency> <!-- 專門用來做業(yè)務(wù)邏輯層 或者 Controller層的測試的 --> <dependency> <groupId>org.easymock</groupId> <artifactId>easymock</artifactId> <version>3.5.1</version> </dependency>
準(zhǔn)備Dao層測試接口,不需要方法的實現(xiàn)
public interface AaDao { void a(); void b(); }
public interface BbDao { void c(); void d(); }
service 測試代碼
public interface ABService { void aa(); void bb(); void cc(); void dd(); }
testService 在此方法中使用 mock 進行測試
public class TestService { private ABService abService = new ABServiceImpl(); }
1. 簡單測試 createMock
@Override public void aa() { aDao.a(); }
測試代碼
@Test public void testAA() { // 創(chuàng)建對象 AaDao aaDao = EasyMock.createStrictMock(AaDao.class); // 記錄 aaDao.a(); EasyMock.expectLastCall(); // 使能設(shè)置 EasyMock.replay(aaDao); // 接下來調(diào)用Service進行測試 abService.setaDao(aaDao); abService.aa(); // 進行校驗 EasyMock.verify(aaDao); }
2. 測試調(diào)用順序 createStrictMock
@Override public void ee() { aDao.b(); aDao.a(); }
測試代碼1
// 測試調(diào)用順序 @Test public void testEE1() { // 創(chuàng)建對象 AaDao aaDao = EasyMock.createMock(AaDao.class); // 進行記錄 aaDao.a(); EasyMock.expectLastCall(); aaDao.b(); EasyMock.expectLastCall(); // 使能設(shè)置,保存記錄信息 EasyMock.replay(aaDao); // 調(diào)用 Service 測試 abService.setaDao(aaDao); abService.ee(); // 進行校驗 EasyMock.verify(aaDao); }
運行此代碼,結(jié)果竟然是正確的,明明調(diào)用順序不一致,卻還是正確,這顯然是不對的
測試代碼2 使用createStrictMock
@Test public void testEE2() { // 創(chuàng)建對象 AaDao aaDao = EasyMock.createStrictMock(AaDao.class); // 進行記錄 aaDao.b(); EasyMock.expectLastCall(); aaDao.a(); EasyMock.expectLastCall(); // 使能設(shè)置,保存記錄信息 EasyMock.replay(aaDao); // 調(diào)用 Service 測試 abService.setaDao(aaDao); abService.ee(); // 進行校驗 EasyMock.verify(aaDao); }
3. 測試方法多次調(diào)用以及調(diào)用順序
@Override public void bb() { aDao.a(); aDao.b(); aDao.b(); aDao.a(); }
測試代碼
@Test public void testBB() { // 創(chuàng)建對象 AaDao aaDao = EasyMock.createStrictMock(AaDao.class); // 記錄 aaDao.a(); EasyMock.expectLastCall(); aaDao.b(); EasyMock.expectLastCall(); aaDao.b(); EasyMock.expectLastCall(); aaDao.a(); EasyMock.expectLastCall(); // 使能設(shè)置,即保存記錄信息 EasyMock.replay(aaDao); // 調(diào)用 Service 測試 abService.setaDao(aaDao); abService.bb(); // 進行校驗 EasyMock.verify(aaDao); }
如果是多次調(diào)用的話,就需要書寫多次記錄
4. 測試調(diào)用不同dao的方法
@Override public void cc() { aDao.a(); bDao.c(); }
測試代碼1
@Test public void testCC1() { // 創(chuàng)建對象 AaDao aaDao = EasyMock.createStrictMock(AaDao.class); BbDao bbDao = EasyMock.createStrictMock(BbDao.class); // 進行記錄 bbDao.c(); EasyMock.expectLastCall(); aaDao.a(); EasyMock.expectLastCall(); // 使能設(shè)置,保存記錄信息 EasyMock.replay(aaDao, bbDao); // 調(diào)用 Service 測試 abService.setaDao(aaDao); abService.setbDao(bbDao); abService.cc(); // 進行校驗 EasyMock.verify(aaDao, bbDao); }
可以看出來,createStrictMock方法并不能保證多個 dao之間的調(diào)用順序,只能對單個的DAO的調(diào)用順序有嚴(yán)格的要求
測試代碼2 createStrictControl
@Test public void testCC2() { // 創(chuàng)建一個 controller,約束這些dao是一個整體 IMocksControl control = EasyMock.createStrictControl(); // 創(chuàng)建對象 AaDao aaDao = control.createMock(AaDao.class); BbDao bbDao = control.createMock(BbDao.class); // 進行記錄 aaDao.a(); EasyMock.expectLastCall(); bbDao.c(); EasyMock.expectLastCall(); // 使能設(shè)置,保存記錄信息 control.replay(); // 調(diào)用 Service 測試 abService.setaDao(aaDao); abService.setbDao(bbDao); abService.cc(); // 進行校驗 control.verify(); }
使用 createStrictControl 定義一個整體,進行多個 dao 的測試
5. 測試不同dao調(diào)用順序及次數(shù)
@Override public void dd() { aDao.a(); bDao.c(); bDao.d(); aDao.a(); }
測試代碼
@Test public void testDD() { // 創(chuàng)建一個 controller,約束這些dao是一個整體 IMocksControl control = EasyMock.createStrictControl(); // 創(chuàng)建對象 AaDao aaDao = control.createMock(AaDao.class); BbDao bbDao = control.createMock(BbDao.class); // 進行記錄 aaDao.a(); EasyMock.expectLastCall(); bbDao.c(); EasyMock.expectLastCall(); bbDao.d(); EasyMock.expectLastCall(); aaDao.a(); EasyMock.expectLastCall(); // 使能設(shè)置,保存記錄信息 control.replay(); // 調(diào)用 Service 測試 abService.setaDao(aaDao); abService.setbDao(bbDao); abService.dd(); // 進行校驗 control.verify(); }
測試此方法時,即便是調(diào)換 同一個dao的方法也會報錯,滿足條件
總結(jié)
測試 service 層時,可以使用 mock 框架進行測試,引入 mock依賴即可,操作簡單
如果測試的 service 只包含一個dao,那么使用 EasyMock.createStrictMock() 即可進行測試
如果測試的 service 包含多個dao,那么使用 EasyMock.createStrictControl(); 創(chuàng)建一個 control 進行包裹即可測試
到此這篇關(guān)于使用Mock進行業(yè)務(wù)邏輯層Service測試詳解的文章就介紹到這了,更多相關(guān)Mock測試Service內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
java8 統(tǒng)計字符串字母個數(shù)的幾種方法總結(jié)(推薦)
下面小編就為大家分享一篇java8 統(tǒng)計字符串字母個數(shù)的幾種方法總結(jié)(推薦),具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來吧2017-11-11Java技能點之SimpleDateFormat進行日期格式化問題
這篇文章主要介紹了Java技能點之SimpleDateFormat進行日期格式化問題,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2023-04-04使用java.util.Timer實現(xiàn)任務(wù)調(diào)度
這篇文章主要為大家詳細介紹了使用java.util.Timer實現(xiàn)任務(wù)調(diào)度,具有一定的參考價值,感興趣的小伙伴們可以參考一下2018-03-03springmvc+Hibernate+JPA(混合事務(wù))解讀
在Spring項目中,Spring Data JPA作為一種持久層框架,因其簡化數(shù)據(jù)庫操作而受到青睞,但在將其引入使用Hibernate的舊項目時,可能會遇到事務(wù)處理問題,解決方案包括配置兩種事務(wù)管理器:Hibernate事務(wù)管理器和JPA事務(wù)管理器2024-09-09如何解決HttpServletRequest.getInputStream()多次讀取問題
這篇文章主要介紹了如何解決HttpServletRequest.getInputStream()多次讀取問題,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教2023-07-07