PowerMock 入门
Posted Firm陈
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了PowerMock 入门相关的知识,希望对你有一定的参考价值。
介绍
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);
@Service
public 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注解的示例注入进来
@InjectMocks
private MockServiceImpl mockService;
@Mock
private MockMapper mockMapper;
/**
* mock普通方法
*/
@Test
public 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)
使用方法
(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(); // 1
ClassThatContainsStaticMethod. 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。
package com.cainiaoguoguo.mocktest.staticmethod;
public class ClassThatContainsStaticMethod
public static String getUserName(int id)
return "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
@Test
public void echoUserName() throws Exception
final String expectResult = "expectResult";
// mock ClassThatContainsStaticMethod类中所有的静态方法
PowerMockito.mockStatic(ClassThatContainsStaticMethod.class);
// 改变方法的行为,当调用getUserName的时候返回expectResult
PowerMockito.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方法返回一个调用其他接口的字符串
package com.cainiaoguoguo.mocktest.finalclass;
public final class StateHolder
public String getState()
return innerMethod("MSG from StateHolder");
private String innerMethod(String msg)
return "INNER: " + msg;
需要测试的StateFormatter类
引用了StateHolder,要对StateFormatter类中的getFormattedState()方法进行测试
package com.cainiaoguoguo.mocktest.finalclass;
public class StateFormatter
private final StateHolder stateHolder;
public StateFormatter(StateHolder stateHolder)
this.stateHolder = stateHolder;
public String getFormattedState()
String safeState = "State information is missing";
final String actualState = stateHolder.getState();
if (actualState != null)
safeState = actualState;
return safeState;
测试类
目的要在调用getFormattedState()方法的过程中让StateHolder的getState()方法返回符合预期的值
package com.cainiaoguoguo.mocktest.finalclass;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.powermock.core.classloader.annotations.PrepareForTest;
import org.powermock.modules.junit4.PowerMockRunner;
import static org.junit.Assert.assertEquals;
import static org.powermock.api.mockito.PowerMockito.mock;
import static org.powermock.api.mockito.PowerMockito.when;
@RunWith(PowerMockRunner.class)
@PrepareForTest(StateHolder.class)
public class StateFormatterTest
@Test
public void getFormattedState() throws Exception
final String expectedState = "state";
StateHolder stateHolderMock = mock(StateHolder.class);
when(stateHolderMock.getState()).thenReturn(expectedState);
StateFormatter tested = new StateFormatter(stateHolderMock);
String actualState = tested.getFormattedState();
assertEquals(expectedState, actualState);
注意:
(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(…)。
import org.junit.Test;
import org.powermock.api.mockito.PowerMockito;
import java.util.ArrayList;
import java.util.List;
public class SpyTest
@Test
public void testSpy()
List list = new ArrayList();
List spy = PowerMockito.spy(list);
// 会抛出IndexOutOfBoundsException异常,因为会去调用spy.get(0)方法。
PowerMockito.when(spy.get(0)).thenReturn("foo");
// 正确的写法如下
PowerMockito.doReturn("foo").when(spy).get(0);
验证行为
普通公有方法
验证方式和静态方法类似,调用Mockito.vertify()就可以进行标准的行为验证
@Test
public 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
@Test
public 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);
// 调用会执行privateMethod
assert(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
@Test
public void testConstruction() throws Exception
final String directoryPath = "mocked path";
File directoryMock = PowerMockito.mock(File.PowerMock+Junit测试小记
使用 Powermock 时出现 NoClassDefFoundError