單元測試可以提高測試開發的效率,減少代碼錯誤率,提高代碼健壯性,提高代碼質量。在Spring框架中常用的兩種測試框架:PowerMockRunner和SpringRunner兩個單元測試,鑒於SpringRunner啟動的一系列依賴和數據連接的問題,推薦使用PowerMockRunner,這樣能有效的提高測試的效率,並且其提供的API能覆蓋的場景廣泛,使用方便,可謂是Java單元測試之模擬利器。
1. PowerMock是什么?
PowerMock是一個Java模擬框架,可用於解決通常認為很難甚至無法測試的測試問題。使用PowerMock,可以模擬靜態方法,刪除靜態初始化程序,允許模擬而不依賴於注入,等等。PowerMock通過在執行測試時在運行時修改字節碼來完成這些技巧。PowerMock還包含一些實用程序,可讓您更輕松地訪問對象的內部狀態。
舉個例子,你在使用Junit進行單元測試時,並不想讓測試數據進入數據庫,怎么辦?這個時候就可以使用PowerMock,攔截數據庫操作,並模擬返回參數。
2. PowerMock包引入
<!-- 單元測試 依賴-->
<dependency>
<groupId>org.powermock</groupId>
<artifactId>powermock-core</artifactId>
<version>2.0.2</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-core</artifactId>
<version>2.23.0</version>
</dependency>
<dependency>
<groupId>org.powermock</groupId>
<artifactId>powermock-module-junit4</artifactId>
<version>2.0.4</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.powermock</groupId>
<artifactId>powermock-api-mockito2</artifactId>
<version>2.0.2</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.github.jsonzou</groupId>
<artifactId>jmockdata</artifactId>
<version>4.3.0</version>
</dependency>
<!-- 單元測試 依賴-->
3. 重要注解說明
@RunWith(PowerMockRunner.class) // 告訴JUnit使用PowerMockRunner進行測試
@PrepareForTest({RandomUtil.class}) // 所有需要測試的類列在此處,適用於模擬final類或有final, private, static, native方法的類
@PowerMockIgnore("javax.management.*") //為了解決使用powermock后,提示classloader錯誤
4. 使用示例
4.1 模擬接口返回
首先對接口進行mock,然后錄制相關行為
InterfaceToMock mock = Powermockito.mock(InterfaceToMock.class)
Powermockito.when(mock.method(Params…)).thenReturn(value)
Powermockito.when(mock.method(Params..)).thenThrow(Exception)
4.2 設置對象的private屬性
需要使用whitebox向class或者對象中賦值。
如我們已經對接口盡心了mock,現在需要將此mock加入到對象中,可以采用如下方法:
Whitebox.setInternalState(Object object, String fieldname, Object… value);
其中object為需要設置屬性的靜態類或對象。
4.3 模擬構造函數
對於模擬構造函數,也即當出現new InstanceClass()時可以將此構造函數攔截並替換結果為我們需要的mock對象。
注意:使用時需要加入標記:
@RunWith(PowerMockRunner.class)
@PrepareForTest({ InstanceClass.class })
@PowerMockIgnore("javax.management.\*")
Powermockito.whenNew(InstanceClass.class).thenReturn(Object value)
4.4 模擬靜態方法
模擬靜態方法類似於模擬構造函數,也需要加入注釋標記。
@RunWith(PowerMockRunner.class)
@PrepareForTest({ StaticClassToMock.class })
@PowerMockIgnore("javax.management.\*")
Powermockito.mockStatic(StaticClassToMock.class);
Powermockito.when(StaticClassToMock.method(Object.. params)).thenReturn(Object value)
4.5 模擬final方法
Final方法的模擬類似於模擬靜態方法。
@RunWith(PowerMockRunner.class)
@PrepareForTest({ FinalClassToMock.class })
@PowerMockIgnore("javax.management.\*")
Powermockito.mockStatic(FinalClassToMock.class);
Powermockito.when(StaticClassToMock.method(Object.. params)).thenReturn(Object value)
4.6 模擬靜態類
模擬靜態類類似於模擬靜態方法。
4.7 使用spy方法避免執行被測類中的成員函數
如被測試類為:TargetClass,想要屏蔽的方法為targetMethod.
1) PowerMockito.spy(TargetClass.class);
2) Powemockito.when(TargetClass.targetMethod()).doReturn()
3) 注意加入
@RunWith(PowerMockRunner.class)
@PrepareForTest(DisplayMoRelationBuilder.class)
@PowerMockIgnore("javax.management.*")
4.8 參數匹配器
有時我們在處理doMethod(Param param)時,不想進行精確匹配,這時可以使用Mockito提供的模糊匹配方式。
如:Mockito.anyInt(),Mockito.anyString()
4.9 處理public void型的靜態方法
Powermockito.doNothing.when(T class2mock, String method, <T>… params>
5. 單元測試用例可選清單
輸入數據驗證:這些檢查通常可以對輸入到應用程序系統中的數據采用。
- 必傳項測試
- 唯一字段值測試
- 空值測試
- 字段只接受允許的字符
- 負值測試
- 字段限於字段長度規范
- 不可能的值
- 垃圾值測試
- 檢查字段之間的依賴性
- 等效類划分和邊界條件測試
- 錯誤和異常處理測試