primo-generator-mock-test
項目位址:
https://github.com/chenhaoxiang/primo介紹
你還在為寫大量單元測試而煩惱嗎,你還在苦苦的建構包裝類的值嗎?這裡有一款mock單元測試代碼自動生成的Maven插件,解決開發人員消耗大量時間在單元測試的問題,全面優化開發人員的測試效率和測試時間。
注意,本插件目前無法完成所有的mock測試,讓你不用修改一行代碼,暫時需要在primo-generator-mock-test生成mock測試代碼的基礎上再進行一點修改,例如分支覆寫,斷言使用。
本插件的目标是:實作讓開發人員不再寫一行mock測試代碼,primo-generator-mock-test幫你全部實作
願景是:減少開發人員的測試負擔,專注業務開發與疊代
經過本人的親自使用,外加我在團隊的内部"推(qiang)廣(tui)"使用,從統計來看,可以減少使用mock測試的小夥伴,至少30-50%的時間。
(此項目目前在我公司幾個團隊使用,節省了團隊成員非常多的單元測試時間,在此分享出來)
使用
1. 首先依賴插件:
最新版本
最新版本:1.0.0-SNAPSHOT
最簡單配置:
<plugin>
<groupId>wiki.primo.generator</groupId>
<artifactId>primo-generator-mock-test-maven-plugin</artifactId>
<version>(版本号)</version>
<configuration>
<testPackageName>(待測試類的包名,0.1.0-SNAPSHOT+支援配置多個,英文分号進行隔開)</testPackageName>
</configuration>
</plugin>
(使用最簡單的配置,即可使用,感覺後面說明過多的不用往下看)
示例:
<plugin>
<groupId>wiki.primo.generator</groupId>
<artifactId>primo-generator-mock-test-maven-plugin</artifactId>
<version>1.0.0-SNAPSHOT</version>
<configuration>
<testPackageName>wiki.primo.generator.primogeneratormocktestdemo.service.impl</testPackageName>
</configuration>
</plugin>
2. 生成測試代碼
在引入插件的項目子產品下運作maven插件的 primo-generator-mock-test:test 指令
mvn primo-generator-mock-test:test
直接運作mvn primo-generator-mock-test:test即可下載下傳模闆檔案&生成測試類
相關配置:
<configPath></configPath>
填寫路徑,相對路徑為目前運作項目的根路徑。(預設下載下傳路徑:/src/main/resources/test/template)
第一次運作運作插件的primo-generator-mock-test:test指令,即可将配置檔案下載下傳到對應的路徑。
可設定配置檔案的檔案名,通過
<configFileName>primo-generator-mock-test.ftl</configFileName>
設定配置檔案的檔案名稱。(預設檔案名稱為primo-generator-mock-test.ftl)
3. 引入mock相關依賴
自動測試代碼生成插件
插件生成的mock測試類方法依賴powermock&mockito,建議直接引入如下依賴(不依賴對于插件的運作沒有影響)
<dependency>
<groupId>wiki.primo.generator</groupId>
<artifactId>primo-generator-mock-test-jar</artifactId>
<version>1.0.0-SNAPSHOT</version>
<scope>test</scope>
</dependency>
4. configuration中相關配置屬性
在引入插件的項目名子產品下,運作插件的megatron:test指令即可在對應的test路徑下生成測試用例。
必填
-
<testPackageName>
:必填)配置需要生成單元測試用例的包名,不要填寫接口所在包名,需要實作類所在包名,會周遊包下以及子包下所有類和類的方法(支援配置多個包名,英文分号隔開不同的包名)。
可以配置單個類。例如:wiki.primo.generator.primogeneratormocktestdemo.service.impl.UserServiceImpl.java
注意,配置單個類一定要以.java結尾。
不支援的類:
- 接口
- 枚舉
- 抽象類
- 私有類
選填
注意:在1.0.0-SNAPSHOT版本之前的jar包未上傳至中央倉庫
1.0.0-SNAPSHOT
-
: json配置檔案路徑,defaultValue = "/src/main/resources/test/template/"<jsonConfigPath>
-
: json配置檔案名稱,defaultValue = "primo-generator-mock-test.json"<jsonConfigFileName>
-
: 是否将Template配置檔案下載下傳到本地,預設true<isDownloadTemplateFile>
-
: 是否将json配置檔案下載下傳到本地,預設true<isDownloadJsonFile>
0.1.1-SNAPSHOT
-
:下載下傳配置檔案的路徑<configPath>
-
:作者名稱<author>
-
:下載下傳下來的配置檔案的名稱<configFileName>
-
:配置testPackageName的包是否遞歸擷取子包下的類(預設true)<isGetChildPackage>
-
:配置是否mock掉父類以及自身測試類非測試的方法(預設true),父類/本類方法調用需要使用this進行調用,目前版本無法支援mock<isMockThisOtherMethod>
-
:配置是否設定基礎類型的值随機生成(預設false)<isSetBasicTypesRandomValue>
-
:配置字元串随機值的位數(例如:"10",表示10位随機字母/數字字元)<setStringRandomRange>
-
:配置int/Integer類型随機值的範圍(例如:"0,1000",表示[0,1000)範圍的int數值,配置固定的值可配置為"0",則int值固定為0 )<setIntRandomRange>
-
:配置long/Long類型随機值的範圍(配置規則與setIntRandomRange類似)<setLongRandomRange>
-
:配置boolean/Boolean類型随機值的範圍(例如:配置為"true"/"false"表示為固定的值,其他任意值表示true和false随機)<setBooleanRandomRange>
版本功能
0.2.1-SNAPSHOT
- fix - 修複在windows下無法生成測試代碼的bug
0.2.0-SNAPSHOT
- 支援配置json,通過json構造參數的值
- 隻支援實際方法的參數指派,mock的參數指派暫時不支援
-
本次隻支援自定義的類型的值進行配置
下面為json配置中屬性的描述:
{ "isOpen": "是否開啟json配置-預設false", "list": [ { "scope":"作用域:全局(global)、包(package)、類(class)、方法(method) - 預設全局", "scopeValue": "作用域的值,global則無需配置該值,package則為包名,class則為類名,method則為方法名", "fullyType": "類型的全限定名稱", "value":{ "若type=base,則該值固定為value":"值", "若type=custom,自定義類型,value下的key為fastjson序列化的屬性名稱":"值" } } ] }
- 删除廢棄的配置
- fix - 修複修改configFileName時無法下載下傳配置檔案的bug
json配置說明
- 可以通過配置json來進行配置某個參數類型的參數值
-
作用域(scope):全局(global)、包(package)、類(class)、方法(method)
參數值配置優先級: 通過插件選填屬性配置 < 全局(global)< 包(package)< 類(class)< 方法(method)
- testPackageName配置多個包,支援分号間換行,空格
- testPackageName可以配置單個實作類。例如:wiki.primo.generator.primogeneratormocktestdemo.service.impl.UserServiceImpl.java 注意,配置單個類一定要以.java結尾。
- 外部依賴隻需要引入primo-generator-mock-test-jar即可。
0.1.0-SNAPSHOT
- 解決參數數量相同,重載方法的mock報錯,進行注釋代碼
- 解決mock方法參數名稱改變問題
- 記憶體中加載内加載器中類,不再需要手動在插件中依賴需要的類,也就是配置第三方依賴不再需要了
- 不需要網絡便可以運作,原來是通過網絡流下載下傳檔案,本版本已經修改為jar包讀取
- 增加測試類目錄可配置
0.0.1
新增/優化功能
- 支援包下所有類中公共非靜态方法生成測試方法
- 支援配置mock的包,将mock掉包下類的所有方法
- 支援基礎類型和包裝類型自動指派
- 增加枚舉參數的支援
- 可進行配置需要跳過的參數類型,直接配置包名,會進行跳過包内所有類的構造(用于跳過接口的構造,直接指派為null)
- 優化全限定名稱為簡稱,使用import導入包,名稱存在重複的類,使用全限定名稱
- 支援配置選擇是否自動mock掉父類&自身非測試的方法 - 預設true
-
支援配置實體基礎類型随機設定/使用預設值空值
a. 随機 String長度:10位數字與字母,使用JDK UUID進行生成,確定唯一
b. 随機 int:[0,1000)
c. 随機 byte:[0,1)
d. 随機 short:[0,127)
e. 随機 double:[0.00,10000.00)
f. 随機 float:[0.00f,10000.00f)
g. 随機 long:[0L,100000L)
g. 随機 char:數字/字母
- 每個測試類使用統一的before注解進行mock方法(考慮到後面每個分支的mock,如果同意進行mock的話,會導緻分支無法全面覆寫)
- mock注解的類,使用了全限定名稱,優化為簡稱,類進行導入,重複類簡稱,第一個類使用簡稱,後面的類使用全限定名稱
- 不再支援配置其他包下的類進行mock,非測試類的所有方法均進行mock,測試類的私有方法也進行mock
- 已生成測試類,不再進行覆寫生成
- 支援第三方包類的加載和構造
- 對于一些沒有setter方法的屬性,也進行了set值;期望:對于沒有setter的屬性值,不進行設定
- 支援字元串、int、long、布爾類型随機值的範圍設定
- 支援配置生成父類屬性的set方法進行設定值,預設true,生成的set方法包含父類的屬性(注意,父類如果不在目前項目中,需要在插件中引入包的依賴)
- 測試類新增方法支援追加生成mock測試方法
- 支援在不同包下的測試類同時進行生成
- 初始化下載下傳配置檔案不再需要,直接運作生成,自動檢測是否下載下傳,未下載下傳先進行下載下傳配置檔案再生成
其他功能排期
- 配置檔案可以配置不進行下載下傳到本地,預設下載下傳
- 支援日志級别設定,友善使用者進行調試
- 支援if-else生成多個mock分支方法
- 方法的參數值支援json檔案進行配置
- 檢測代碼實作類的方法覆寫率百分比檢視以及通知到釘釘群
- 支援簡單集合構造指派
- 支援配置靜态方法mock,需要進行配置靜态類的全限定名稱(靜态方法不建議進行mock)
- 測試類中的私有方法進行mock,私有方法專門開方法進行生成mock測試,預設不支援,需要配置(私有方法不建議進行mock)
- 同一個測試方法中存在Mock方法名稱重複(參數個數不同)無法進行區分,僅僅對于第一個方法進行mock,且會存在重複mock代碼生成;期望:支援同名方法的mock
- 無法支援重名方法(參數個數相同,參數類型不同),會出現生成的mock方法引用不明确;期望:mock方法引用明确(通過比對參數類型解決)
- 不支援嵌套自定義參數的構造;期望:支援多級參數的構造
- 不支援集合的構造;期望:支援集合的構造
- mock方法傳回值不支援自定義,統一是傳回null;期望:支援mock傳回值的自定義/生成值
- 不支援Spring自定義事務管理器DataSourceTransactionManager的mock;期望:支援自定義事務的mock
- 支援多級參數構造指派
- 支援重載方法的mock
- 支援斷言配置
- 參數值的配置yml檔案
- 生成的測試方法可以配置是否編譯報錯,強制開發者主動進行單元測試
注意
配置mock靜态方法:
預設使用@RunWith(MockitoJUnitRunner.class),如果配置了mock靜态方法,将使用@RunWith(PowerMockRunner.class)。
使用PowerMockRunner與MockitoJUnitRunner類,都無法支援父類中的屬性(service的實作類中又同時注入了該類)自動注入的mock(例如mybatis中service層的泛型父類中的泛型baseMapper)。這是由于Mock類會将這兩個類作為不同的執行個體來進行處理,隻會mock掉你注入service實作類的基類,而無法注入service實作類的父類中的mapper。
例如:
service實作類
public class WorkFlowServiceImpl extends ServiceImpl<WorkFlowMapper, WorkFlowEntity> implements IWorkFlowService {
@Autowired
private WorkFlowMapper workFlowMapper;
//...
}
父類ServiceImpl:
public class ServiceImpl<M extends BaseMapper<T>, T> implements IService<T> {
@Autowired
protected M baseMapper;
//...
}
在WorkFlowServiceImpl中使用時:
baseMapper.deleteById("1");
在mock測試類中:
@RunWith(PowerMockRunner.class)
@PowerMockIgnore("javax.management.*")
@PrepareForTest({BeanConvertUtil.class, FieldBaseDto.class})
public class WorkFlowServiceImplTest {
@InjectMocks
private WorkFlowServiceImpl workFlowServiceImpl;
@Mock
private WorkFlowMapper workFlowMapper;
//...
}
無法進行mock掉baseMapper執行個體,這是由于baseMapper與workFlowMapper并不是同一個執行個體!這裡僅僅隻能mock掉workFlowMapper。
目前可以在service層的實作類中将baseMapper再次注入,則使用PowerMockRunner.class也可以進行mock
service層的實作類不推薦使用泛型基類service父類進行調用泛型mapper操作資料庫層!可以選擇注入Mapper再進行調用。
使用體驗
199個測試方法,一共覆寫309個被測試方法,使用primo-generator-mock-test生成後,僅僅隻使用了3個多小時進行mock優化(僅僅優化了運作報錯的方法,沒有進行完善分支測試)。
按照我以前的經驗,如果全部由自己寫,一切順利的情況下,199個方法的mock測試,至少要多出幾倍的時間。
(此測試項目為使用mybatis-plus的項目,service層的實作類非常多的方法直接使用了父類方法,導緻mock很麻煩,耽擱了一些時間,其他項目相對而言會節省更多時間)
測試類:
