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更适合自己服务器端的测试用例使用