powermock测试框架

  1. 1.简介
    1. 1-1.功能
    2. 1-2.实现原理
  2. 2.简单使用
    1. 2-1.pom
    2. 2-2.静态方法
    3. 2-3.私有方法
    4. 2-4.final方法
    5. 2-5.void方法
  3. 3.实战
    1. 3-1.业务代码
    2. 3-2.测试类
  4. 4.扩展链接

1.简介

Mockito优点

通过在执行后校验哪些函数已经被调用,消除了对期望行为(expectations)的需要。

Mockito缺陷

不提供对静态方法、构造方法、私有方法以及Final方法的模拟支持

PowerMock 也是一个单元测试模拟框架,它是在其它单元测试模拟框架的基础上做出的扩展。通过提供定制的类加载器以及一些字节码篡改技巧的应用,
PowerMock 现了对静态方法、构造方法、私有方法以及 Final 方法的模拟支持,对静态初始化过程的移除等强大的功能。

目前,PowerMock 仅支持EasyMockMockito

本文的目的就是和大家一起学习在 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测试框架s
  • MockitoAnnotations.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" 转载请保留原文链接及作者。

目录
×

喜欢就点赞,疼爱就打赏

pgmanor iworkh gitee