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

