PowerMock的使用
之所以提到PowerMock而不是Mock,是因爲自己服務器端的配置數據獲取的方法是靜態方法,如果使用mock方式來模擬數據,只有PowerMock支持Mock靜態方法,Mock不支持。
引入PowerMock
<dependency>
<groupId>org.powermock</groupId>
<artifactId>powermock-module-junit4</artifactId>
<version>2.0.0</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.powermock</groupId>
<artifactId>powermock-api-mockito2</artifactId>
<version>2.0.0</version>
<scope>test</scope>
</dependency>
編寫測試用例
@RunWith(PowerMockRunner.class) //該註解表示當前測試類的運行模式爲PowerMock,不加這個註解,PowerMock不生效
@PrepareForTest({ NumericService.class }) //該註解表示要在當前測試類中進行Mock的類
@PowerMockIgnore({ "javax.management.*", "javax.crypto.*", "sun.security.ssl.*", "sun.security.jca.*", "javax.net.*" })//本行註解要求PowerMock使用自定義ClassLoader加載時,忽略一部分底層包,否則會出現各種“class not cast to”之類的諸多報錯
public class PowerMockTest {
@Test
public void test() throws Exception {
long time = System.currentTimeMillis();
TestUtility.init();
System.out.println(System.currentTimeMillis() - time);
try {
NumericService.getNumericById(TabShop.class, "forTest");
fail();
} catch (Exception e) {
}
PowerMockito.mockStatic(NumericService.class);
PowerMockito.when(NumericService.getNumericById(TabShop.class, "forTest")).thenReturn(null);
System.out.println(NumericService.getNumericById(TabShop.class, "forTest"));
}
}
運行代碼查看運行效果,已經是否Mock成功。
17:11:54.117 [main] ERROR com.***.utli.TestUtility - NCC Server started…
17:11:54.129 [main] INFO com.***.gs.common.JobThreadPoolExecutor - init corePoolSize:10
64269
null
17:11:54.931 [Thread-4] ERROR gamebase.base.server.BaseServer - Execute ShutdownHook Start
17:11:54.932 [Thread-4] ERROR gamebase.base.server.BaseServer - Execute ShutdownHook End
可見PowerMock已經成功將 NumericService.getNumericById(TabShop.class, "forTest")
Mock住,並將返回值設置成null。
但是,注意在null值前面的數值,表示TestUtility.init();
運行的時間,高達64秒,太耗時了,這是因爲在TestUtility.init();
中初始化了很多東西,PowerMock下運行時導致性能嚴重下降,基於這個原因,後來又找到JMock來實現對數據獲取的模擬。
JMockit的使用
引入JMockit
<!-- 先聲明jmockit的依賴 -->
<dependency>
<groupId>org.jmockit</groupId>
<artifactId>jmockit</artifactId>
<version>1.36</version>
<scope>test</scope>
</dependency>
<!-- 再聲明junit的依賴 -->
編寫測試用例
public class JMockTest {
@Test
public void testExpectations() {
try {
NumericService.getNumericById(TabShop.class, "2");
fail();
} catch (Exception e) {
}
new Expectations(NumericService.class) {
{
NumericService.getNumericById(TabShop.class, "2");
result = null;
}
};
System.out.println(NumericService.getNumericById(TabShop.class, "2"));
}
@Test
public void testMockUp() {
try {
NumericService.getNumericById(TabShop.class, "1");
fail();
} catch (Exception e) {
}
new MockUp<NumericService>() {
@Mock
public <T> T getNumericById(Class<T> clz, String numericId) {
return null;
}
};
System.out.println(NumericService.getNumericById(TabShop.class, "1"));
}
}
Expectations
和MockUp
的測試用例都能跑通,在這裏不在貼上結果。不過可以看到,JMockit的使用比起PowerMock更加輕量級,不需要對類進行整個註解,而是在單個測試用例中使用new的方式進行修改。
比較
比較項目 | PowerMock | JMockit |
---|---|---|
使用便捷度 | 需要對整個測試類做註解 | 在單個測試用例中使用即可 |
調用Mock後的方法10000遍消耗的時間(毫秒) | 1278 | 483 |
準確度 | 目前所知,PowerMock後的靜態方法所有返回值都是Mock的值 | 支持指定參數的指定返回值,不符合參數值的調用不走Mock |
生命週期 | 從類的加載到結束 | 從調用new到當前測試用例結束 |
機制 | 自定義ClassLoader加載測試類,並處理類中所有的引用,包括底層甚至JDK部分代碼 | 通過字節碼處理,生成替換類,不對其他引用出處理 |
通過以上比較,目前確認JMockit更適合自己服務器端的測試用例使用