powermock测试框架
1.简介
Mockito优点
通过在执行后校验哪些函数已经被调用,消除了对期望行为(expectations)的需要。
Mockito缺陷
不提供对静态方法、构造方法、私有方法以及Final方法的模拟支持
PowerMock 也是一个单元测试模拟框架,它是在其它单元测试模拟框架的基础上做出的扩展。通过提供定制的类加载器以及一些字节码篡改技巧的应用,
PowerMock 现了对静态方法、构造方法、私有方法以及 Final 方法的模拟支持,对静态初始化过程的移除等强大的功能。
目前,PowerMock 仅支持EasyMock
和Mockito
。
本文的目的就是和大家一起学习在 Mockito 框架上扩展的 PowerMock 的强大功能。
1-1.功能
PowerMock也是一个单元测试模拟框架,它是在其它单元测试模拟框架的基础上做出的扩展。通过提供定制的类加载器以及一些字节码篡改技巧的应用。
- 对静态方法
- 构造方法
- 私有方法
- final方法
- 静态初始化
1-2.实现原理
当某个测试方法被注解@PrepareForTest标注以后,在运行测试用例时,会创建一个新的org.powermock.core.classloader.MockClassLoader实例,然后加载该测试用例使用到的类(系统类除外)。
PowerMock会根据你的mock要求,去修改写在注解@PrepareForTest里的class文件(当前测试类会自动加入注解中),以满足特殊的mock需求。例如:去除final方法的final标识,在静态方法的最前面加入自己的虚拟实现等。
如果需要mock的是系统类的final方法和静态方法,PowerMock不会直接修改系统类的class文件,而是修改调用系统类的class文件,以满足mock需求。
2.简单使用
下面主要以静态方法和私有方法进行演示使用
2-1.pom
<dependencies>
<dependency>
<groupId>org.powermock</groupId>
<artifactId>powermock-api-mockito</artifactId>
<version>1.7.4</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.powermock</groupId>
<artifactId>powermock-module-testng</artifactId>
<version>1.7.4</version>
<scope>test</scope>
</dependency>
</dependencies>
注意这版本选择要统一,别不一样。(我开始就用不一样的,怎么试都报错🤣)
2-2.静态方法
静态方法
public class PowerMockDemo {
public static String staticMethod(){
System.out.println("call...staticMethod");
throw new RuntimeException("staticMethod--没有实现");
}
}
测试
@PrepareForTest(PowerMockDemo.class)
public class PowerMockTest {
@ObjectFactory
public IObjectFactory getObjectFactory() {
return new PowerMockObjectFactory();
}
@Test
public void testStaticMethod() throws Exception {
// mock静态类
PowerMockito.mockStatic(PowerMockDemo.class);
// 打桩
// 写法一
// PowerMockito.when(PowerMockDemo.staticMethod()).thenReturn("1");
// 写法二
PowerMockito.doReturn("1").when(PowerMockDemo.class,"staticMethod");
// 比较结果
Assert.assertEquals("1", PowerMockDemo.staticMethod());
}
}
@ObjectFactory
: 必须要使用,相当于junit里的@RunWith(PowerMockRunner.class)
PowerMockito.mockStatic
:mockStatic静态方法
2-3.私有方法
私有方法
public class PowerMockDemo {
private String privateMethod(String param1, String param2){
System.out.println("call...privateMethod");
throw new RuntimeException("privateMethod--没有实现");
}
}
测试
@PrepareForTest(PowerMockDemo.class)
public class PowerMockTest {
@ObjectFactory
public IObjectFactory getObjectFactory() {
return new PowerMockObjectFactory();
}
@Test
public void testPrivateMethod() throws Exception {
// 私有方法打桩
PowerMockDemo mock = PowerMockito.mock(PowerMockDemo.class);
// 写法一
// PowerMockito.when(mock, "privateMethod", Mockito.anyString(), Mockito.anyString()).thenReturn("111");
// 写法二
PowerMockito.doReturn("111").when(mock, "privateMethod", Mockito.anyString(), Mockito.anyString());
// 私有方法调用
Method privateMethod = PowerMockito.method(PowerMockDemo.class, "privateMethod", String.class, String.class);
Object result = privateMethod.invoke(mock, "iworkh", "沐雨云楼");
// 比较结果
Assert.assertEquals("111", result);
}
}
- 打桩使用使用了多个参数,并指定私有方法名和参数
PowerMockito.method
来生成反射Method
,然后调用invoke
方法来调用方法
2-4.final方法
final方法
public class PowerMockDemo {
public final String finalMethod(){
System.out.println("call...finalMethod");
throw new RuntimeException("finalMethod--没有实现");
}
}
测试
@PrepareForTest(PowerMockDemo.class)
public class PowerMockTest {
@ObjectFactory
public IObjectFactory getObjectFactory() {
return new PowerMockObjectFactory();
}
@Test
public void testFinalMethod() {
PowerMockDemo mock = PowerMockito.mock(PowerMockDemo.class);
// 写法一
// PowerMockito.when(mock.finalMethod()).thenReturn("final 22");
// 写法二
PowerMockito.doReturn("final 22").when(mock).finalMethod();
String result = mock.finalMethod();
// 比较结果
Assert.assertEquals("final 22", result);
}
}
final很普通,就不多讲了
2-5.void方法
void方法
public class PowerMockDemo {
public void noReturnMethod() {
System.out.println("call...noReturnMethod");
throw new RuntimeException("noReturnMethod--没有实现");
}
}
测试
@PrepareForTest(PowerMockDemo.class)
public class PowerMockTest {
@ObjectFactory
public IObjectFactory getObjectFactory() {
return new PowerMockObjectFactory();
}
@Test
public void testNoReturnMethod() {
PowerMockDemo mock = PowerMockito.mock(PowerMockDemo.class);
PowerMockito.doNothing().when(mock).noReturnMethod();
mock.noReturnMethod();
}
}
3.实战
上面例子,只是简单的使用,我们来看下powermock和mockito结合,如何使用。
3-1.业务代码
实体类
public class Employee {
private int empno;
private String ename;
private Date hiredate;
private double sal;
...省略setter、getter、构造方法...
}
dao
public class EmployeeDao {
public Employee getEmpById(int id) {
System.out.println("EmployeeDao--get");
throw new RuntimeException("TODO--EmployeeDao--getEmpById--还没有来得及写");
}
}
dao里的方法还没有实装
工具类
public class DataProcessTool {
public static void hiddenSomething(Employee employee) {
throw new RuntimeException("TODO---hiddenSomething--还没有来得及写");
}
}
工具类里的方法还没有实装
service
public class EmployeeService {
private EmployeeDao employeeDao;
public Employee getEmp(int id) {
Employee emp = employeeDao.getEmpById(id);
add(2,3);
DataProcessTool.hiddenSomething(emp);
return emp;
}
private int add(int a, int b) {
System.out.println("私有方法被调用add");
return a + b;
}
}
service里私有方法、静态方法都没有实装。
- hiddenSomething: 静态方法,相当于我们工具类调用,还没写好。
- add: 实装好的私有方法,主要演示如何私有方法调用
- getEmps: 调用私有方法和工具类的静态方法,还调用了dao的方法。
3-2.测试类
@PrepareForTest({EmployeeService.class, EmployeeDao.class, DataProcessTool.class})
public class EmployeeServiceTest {
@Mock
private EmployeeDao employeeDao;
@InjectMocks
private EmployeeService employeeService;
@BeforeClass
public void init() throws Exception {
MockitoAnnotations.initMocks(this);
}
@ObjectFactory
public IObjectFactory getObjectFactory() {
return new PowerMockObjectFactory();
}
@Test(priority = 1)
public void testSayPrivate() throws Exception {
// 私有方法调用
Method privateMethod = PowerMockito.method(EmployeeService.class, "add", int.class, int.class);
Object result = privateMethod.invoke(employeeService, 3, 5);
System.out.println(result);
Assert.assertEquals(8, result);
}
@Test(priority = 2)
public void testGetEmp() throws Exception {
// 静态方法打桩 (无返回值)
PowerMockito.mockStatic(DataProcessTool.class);
PowerMockito.doNothing().when(DataProcessTool.class, "hiddenSomething", Mockito.any());
// mock对象的普通方法
Employee emp = new Employee(10, "沐雨云楼", new Date(), 2000);
PowerMockito.doReturn(emp).when(employeeDao).getEmpById(Mockito.anyInt());
// 调用
Employee result = employeeService.getEmp(10);
Assert.assertEquals("沐雨云楼", result.getEname());
}
}
主要需要注意以下几点:
@PrepareForTest
: 将所有的需要mock的类定义下@Mock
和@InjectMocks
: Mockito内容,可以看mockito测试框架sMockitoAnnotations.initMocks(this)
: Mockito内容,注解初始化- 私有方法测试,静态方法(无返回值)如何打桩
4.扩展链接
转载请注明来源,欢迎指出任何有错误或不够清晰的表达。可以在下面评论区评论,也可以邮件至 157162006@qq.com
文章标题:powermock测试框架
字数:1.6k
本文作者:沐雨云楼
发布时间:2020-08-23, 12:45:17
最后更新:2020-09-17, 21:53:30
原始链接:https://iworkh.gitee.io/blog/2020/08/23/java-powermock/版权声明: "署名-非商用-相同方式共享 4.0" 转载请保留原文链接及作者。