PowerMock 入门
文章目錄
- 介紹
- Mock測試
- 好處-- 模擬數據
- 好處--減少依賴
- 包導入
- 示例
- 常用注解
- @RunWith(PowerMockRunner.class)
- @PrepareForTest({UserController.class})
- @PowerMockIgnore(“javax.management.*”)
- 常用行為錄制模式
- when(…).thenXXX()
- doXXX(…).when(mockObj)
- Mock靜態方法
- 使用方法
- 驗證行為
- 使用參數匹配
- 拋出異常
- 非私有方法
- 私有方法
- 示例
- Mock Final關鍵字
- 說明
- 實例
- 局部Mock
- 說明
- 驗證行為
- 普通公有方法
- 驗證私有方法
- Mock構造函數
- 說明
- 示例
介紹
PowerMock是一個Java模擬框架,用于解決測試問題。
PowerMock 由Mockito和EasyMock兩部分API構成,它必須要依賴測試框架。
當前PowerMock支持Junit和TestNG.兩種測試框架。
針對Junit又有三種不同的執行器對應JUnit4.4+、JUnit4.0-4.3和JUnit 3。
TestNG的執行器實現只有一個版本,但是需要依賴TestNG5.11+版本。
Mock測試
Mock 測試就是在測試過程中,對于某些不容易構造(如 HttpServletRequest 必須在Servlet 容器中才能構造出來)或者不容易獲取比較復雜的對象(如 JDBC 中的ResultSet 對象),用一個虛擬的對象(Mock 對象)來創建以便測試的測試方法。
好處-- 模擬數據
在使用Junit進行單元測試時,不想讓測試數據進入數據庫,可以使用PowerMock,攔截數據庫操作,并模擬返回參數。
好處–減少依賴
代碼存在如下依賴:
當需要測試A類的時候,如果沒有Mock,則需要把整個依賴樹都構建出來,而使用Mock的話就可以將結構分解開
包導入
Junit 4.4+ (不同包導入會有差異)
<!-- PowerMock JUnit 4.4+ Module --> <dependency><groupId>org.powermock</groupId><artifactId>powermock-module-junit4</artifactId><version>2.0.0</version><scope>test</scope> </dependency> <!-- PowerMock Mockito2 API --> <dependency><groupId>org.powermock</groupId><artifactId>powermock-api-mockito2</artifactId><version>2.0.0</version><scope>test</scope> </dependency> <dependency><groupId>junit</groupId><artifactId>junit</artifactId><version>4.11</version><scope>test</scope> </dependency>示例
/***********************Prepare****************************/ public interface MockMapper { public int count(MockModel model); }@Servicepublic class MockServiceImpl { @Autowired private MockMapper mockMapper; public int count(MockModel model) { return mockMapper.count(model); } } /*****************************************************/ @RunWith(PowerMockRunner.class) // 告訴JUnit使用PowerMockRunner進行測試 @PrepareForTest({MockUtil.class}) // 所有需要測試的類列在此處,適用于模擬final類或有final, private, static, native方法的類 @PowerMockIgnore("javax.management.*") //為了解決使用powermock后,提示classloader錯誤 public class MockExample {// 將@Mock注解的示例注入進來@InjectMocksprivate MockServiceImpl mockService;@Mockprivate MockMapper mockMapper;/*** mock普通方法*/@Testpublic void testSelectAppAdvertisementList() {MockModel model = new MockModel();PowerMockito.when(mockMapper.count(model)).thenReturn(2);Assert.assertEquals(2, mockService.count(model));} }常用注解
@RunWith(PowerMockRunner.class) // 告訴JUnit使用PowerMockRunner進行測試 @PrepareForTest({RandomUtil.class}) // 所有需要測試的類列在此處,適用于模擬final類或有final, private, static, native方法的類 @PowerMockIgnore("javax.management.*") //為了解決使用powermock后,提示classloader錯誤@RunWith(PowerMockRunner.class)
該注解需要在測試類上添加,告訴JUnit使用PowerMock執行器,一般來說都添加上。
@PrepareForTest({UserController.class})
所有需要測試的類,列在此處,以逗號分隔。測試靜態方法、私有方法、final方法、使用System/Bootstrap類加載器加載的類和mock構造方法時需要添加該注解。
注意:@PrepareForTest中包含的類不會被LLT統計到代碼覆蓋。
@PowerMockIgnore(“javax.management.*”)
為了解決使用powermock后,提示classloader錯誤。
常用行為錄制模式
when(…).thenXXX()
doXXX(…).when(mockObj)
Mock靜態方法
使用方法
(1)在測試類上加入@RunWith(PowerMockRunner.class)(該注解告訴JUnit使用PowerMock執行器)和@ PrepareForTest(Static.class)注解.
(2)使用PowerMock.mockStatic(Static.class)可以mock Static類中所有的靜態方法。也可以使用PowerMockito.spy(class)方法來對特定的方法mock.
(3)調用Mockito.when()來錄制行為。
驗證行為
要驗證靜態方法是否有被執行,可以使用PowerMockito.verifyStatic(Mockito.times(1)),每驗證一個函數都需要先調用一次PowerMockito.verifyStatic(…)函數:
(1)調用PowerMockito.verifyStatic()方法開始驗證行為,不傳參數默認是驗證調用一次,要校驗調用多次傳入Mockito.times(…)即可。
(2)PowerMockito.verifyStatic()之后,調用需要驗證的靜態方法即可完成驗證。
PowerMockito.verifyStatic(); // 1ClassThatContainsStaticMethod. getUserName (param); // 2使用參數匹配
Mockito的參數匹配仍舊適用于PowerMock
PowerMockito.verifyStatic();Static.thirdStaticMethod(Mockito.anyInt());拋出異常
非私有方法
PowerMockito.doThrow(new ArrayStoreException("Mock error")).when(StaticService.class);私有方法
由于不能直接訪問方法,可以將方法名以字符串的形式告訴powermock進行調用
when(tested, "methodToExpect", argument).thenReturn(myReturnValue);when(tested, "methodToExpect", argument).thenThrow(new ArrayStoreException("Mock error"));示例
類ClassThatContainsStaticMethod
存在一個靜態方法getUserName()返回一個字符串:UserName:id。
對ClassThatContainsStaticMethod.getUserName()進行mock
package com.cainiaoguoguo.mocktest.staticmethod;import org.junit.Test;import org.junit.runner.RunWith;import org.mockito.Mockito;import org.powermock.api.mockito.PowerMockito;import org.powermock.core.classloader.annotations.PrepareForTest;import org.powermock.modules.junit4.PowerMockRunner;import static org.junit.Assert.*;@RunWith(PowerMockRunner.class)@PrepareForTest(ClassThatContainsStaticMethod.class)public class StaticMethodTest {@Testpublic void echoUserName() throws Exception {final String expectResult = "expectResult";// mock ClassThatContainsStaticMethod類中所有的靜態方法PowerMockito.mockStatic(ClassThatContainsStaticMethod.class);// 改變方法的行為,當調用getUserName的時候返回expectResultPowerMockito.when(ClassThatContainsStaticMethod.getUserName(Mockito.anyInt())).thenReturn(expectResult);assert(ClassThatContainsStaticMethod.getUserName(123).equals(expectResult));// true}}首先添加了@RunWith(PowerMockRunner.class)和@PrepareForTest(ClassThatContainsStaticMethod.class)兩個注解
然后調用PowerMockito.mockStatic對靜態方法進行mock
接下來調用when…then…模式對方法行為進行錄制
調用getUserName方法判斷返回結果。
綜合示例
/************************Prepare****************************/ public class MockUtil {private static final Random random = new Random();public static int nextInt(int bound) {return random.nextInt(bound);} } /***************************************************/@RunWith(PowerMockRunner.class) // 告訴JUnit使用PowerMockRunner進行測試 @PrepareForTest({MockUtil.class}) // 所有需要測試的類列在此處,適用于模擬final類或有final, private, static, native方法的類 @PowerMockIgnore("javax.management.*") //為了解決使用powermock后,提示classloader錯誤 public class MockExample {@Test public void testStaticMethod() { PowerMockito.mockStatic(MockUtil.class); PowerMockito.when(MockUtil.nextInt(10)).thenReturn(7); Assert.assertEquals(7, MockUtil.nextInt(10)); }}Mock Final關鍵字
說明
(1)需要添加@RunWith(PowerMockRunner.class)注解和@PrepareForTest(ClassWithFinal.class)注解
(2)調用PowerMock.mock(ClassWithFinal.class)方法來mock final類的所有方法的,調用該方法將返回一個mock對象(暫且叫他mockObject)。
實例
final類StateHolder
提供一個getState方法返回一個調用其他接口的字符串
需要測試的StateFormatter類
引用了StateHolder,要對StateFormatter類中的getFormattedState()方法進行測試
測試類
目的要在調用getFormattedState()方法的過程中讓StateHolder的getState()方法返回符合預期的值
注意:
(1)需要添加@RunWith(PowerMockRunner.class)和@PrepareForTest(StateHolder.class)注解;
(2)調用PowerMockito.mock()方法mock需要被攔截的類;
(3)使用when…thenReturn…的模式返回期望得到的值。
局部Mock
說明
PowerMockito.spy():不mock一個類中的所有方法,而是mock部分方法
使用場景:當要真實調用某些方法。
注意:
使用spy來錄制行為的時候使用when(…).thenXxx(…)的模式會直接調用原有方法,可能會和預期的結果不符合。正確的使用方式是doXXX(…).when(…).methodToMock(…)。
驗證行為
普通公有方法
驗證方式和靜態方法類似,調用Mockito.vertify()就可以進行標準的行為驗證
@Testpublic void testSpy() {List list = new ArrayList();List spy = PowerMockito.spy(list);PowerMockito.doReturn("foo").when(spy).get(0);spy.get(0);spy.get(0);Mockito.verify(spy, Mockito.times(2)).get(0); //驗證spy.get(0)是否被調用兩次}驗證私有方法
驗證私有方法使用PowerMockito.verifyPrivate()即可,該方法對靜態私有方法也適用
import org.junit.Test;import org.junit.runner.RunWith;import org.mockito.Mockito;import org.powermock.api.mockito.PowerMockito;import org.powermock.core.classloader.annotations.PrepareForTest;import org.powermock.modules.junit4.PowerMockRunner;@RunWith(PowerMockRunner.class)@PrepareForTest({PartialMockClass.class})public class SpyTest {@Testpublic void verifyPrivate() throws Exception {final String expectResult = "MESSAGE";String param = "param string";PartialMockClass classUnderTest = PowerMockito.spy(new PartialMockClass());PowerMockito.doReturn(expectResult).when(classUnderTest, "privateMethod", param);// 調用會執行privateMethodassert(classUnderTest.publicMethod(param).equals(expectResult));// 使用PowerMockito.verify()驗證調用PowerMockito.verifyPrivate(classUnderTest, Mockito.times(1)).invoke("privateMethod", param);}}class PartialMockClass {public String publicMethod(String msg) {return privateMethod(msg);}private String privateMethod(String msg) {return "MSG:" + msg;}}Mock構造函數
說明
能模擬構造函數從而使被測代碼中 new 操作返回的對象可以被隨意定制
會很大程度的提高單元測試的效率。
使用的形式是whenNew(MyClass.class).with[No|Any]Arguments().thenXXX(…)
示例
import org.junit.Test;import org.junit.runner.RunWith;import org.powermock.api.mockito.PowerMockito;import org.powermock.core.classloader.annotations.PrepareForTest;import org.powermock.modules.junit4.PowerMockRunner;import java.io.File;@RunWith(PowerMockRunner.class)@PrepareForTest({DirectoryStructure.class})public class ConstructionTest {@Testpublic void testConstruction() throws Exception {final String directoryPath = "mocked path";File directoryMock = PowerMockito.mock(File.class);// mock File的構造函數PowerMockito.whenNew(File.class).withArguments(directoryPath).thenReturn(directoryMock);// 錄制行為PowerMockito.when(directoryMock.exists()).thenReturn(false);PowerMockito.when(directoryMock.mkdirs()).thenReturn(true);// 調用測試assert(new NewFileExample().createDirectoryStructure(directoryPath));// 驗證行為PowerMockito.verifyNew(File.class).withArguments(directoryPath);}}class NewFileExample {public boolean createDirectoryStructure(String path) {DirectoryStructure directoryStructure = new DirectoryStructure();return directoryStructure.create(path);}}class DirectoryStructure {public boolean create(String directoryPath) {File directory = new File(directoryPath);if (directory.exists()) {throw new IllegalArgumentException("\"" + directoryPath + "\" already exists.");}return directory.mkdirs();}}總結
以上是生活随笔為你收集整理的PowerMock 入门的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 解决 Unable to determi
- 下一篇: Flutter 加载WebView(加载