PowerMock 学习


文章目录

  • PowerMock 学习
  • 1. 🍢为什么要使用PowerMock
  • 2. 🌿PowerMock简介
  • 3.🌱 PowerMock 基本用法
  • 3.1 创建测试的单元类
  • 3.2 单元测试类
  • 4. 🌵Mock局部变量的详细讲解
  • 4.1 局部变量类方法
  • 4.2. 单元测试
  • 5. 📔Mock 静态方法
  • 5.1 静态方法类
  • 5.2 单元测试
  • 6. 📕final修饰的类
  • 6.1 final 方法类
  • 6. 2 单元测试类
  • 7. 📗verify的使用
  • 7.1 verify service 类
  • 7.2 单元测试类
  • 8. 📘Mock 构造函数的使用
  • 8.1 构造类
  • 8.2 单元测试类
  • 9. ✂️ArgumentsMather 的使用
  • 9.1 单元类方法
  • 9.2 单元测试
  • 10 📌Answer 不同参数返回不同结果
  • 11. 🍄Spy使用
  • 11.1 spy 单元类
  • 11.2 单元测试
  • 12 🌾私有方法的Mock
  • 12.1 单元类
  • 12.2 单元测试类
  • 🌵附件


1. 🍢为什么要使用PowerMock

现如今比较流行的Mock工具如jMock、EasyMock 、Mockito等都有一个共同的缺点:不能mock静态、final、私有方法等。而PowerMock能够完美的弥补以上三个Mock工具的不足。

2. 🌿PowerMock简介

PowerMock是一个扩展了其它如EasyMock等mock框架的、功能更加强大的框架。PowerMock使用一个自定义类加载器和字节码操作来模拟静态方法,构造函数,final类和方法,私有方法,去除静态初始化器等等。通过使用自定义的类加载器,简化采用的IDE或持续集成服务器不需要做任何改变。熟悉PowerMock支持的mock框架的开发人员会发现PowerMock很容易使用,因为对于静态方法和构造器来说,整个的期望API是一样的。PowerMock旨在用少量的方法和注解扩展现有的API来实现额外的功能。目前PowerMock支持EasyMock和Mockito。

3.🌱 PowerMock 基本用法

3.1 创建测试的单元类

public class User {}
public class UserDao {

    public int getUserCount() {

        throw new UnsupportedOperationException();
    }

    public void saveUser( User user) {

        throw new UnsupportedOperationException();
    }
}
public class UserService {

    private UserDao userDao;

    public UserService(UserDao userDao) {
        this.userDao = userDao;
    }

    public int getUserCount() {

        return userDao.getUserCount();
    }

    public void saveUser(User user) {

        userDao.saveUser(user);
    }
}

3.2 单元测试类

import org.junit.Before;
import org.junit.Ignore;
import org.junit.Test;
import org.mockito.Mock;
import org.mockito.Mockito;
import org.mockito.MockitoAnnotations;
import org.powermock.api.mockito.PowerMockito;

import javax.management.OperationsException;

import static org.junit.Assert.*;

public class UserServiceTest {

    private UserService userService;

    @Before
    public void setUp() {

        userService = new UserService(new UserDao());
    }

    @Mock
    private UserDao userDao;

    // powermock  单元测试
    @Test
    public void getUserCountWithPowerMock() {
        UserDao uDao = PowerMockito.mock(UserDao.class);
        //PowerMockito.doReturn(10).when(uDao).getUserCount();
        // 错误语法
        //PowerMockito.doReturn(10).when(uDao.getUserCount());
        // 或者写法
        PowerMockito.when(uDao.getUserCount()).thenReturn(10);
        UserService userService = new UserService(uDao);
        int userCount = userService.getUserCount();


        assertEquals(10, userCount);
    }

     // mock  单元测试
    @Ignore
    @Test
    public void getUserCountWithMockito() {
        MockitoAnnotations.initMocks(this);
        UserService userService = new UserService(userDao);
        Mockito.when(userDao.getUserCount()).thenReturn(10);

        int userCount = userService.getUserCount();

        assertEquals(10, userCount);
    }

     // junit  单元测试
    @Ignore
    @Test
    public void getUserCountWithJunit() {
        try {
            userService.getUserCount();

            fail("should not be here");
        } catch (Exception e) {

            assertTrue(e instanceof UnsupportedOperationException);
        }

    }

    // junit  单元测试
    @Ignore
    @Test
    public void saveUserWithJunit() {
        try {
            userService.saveUser(new User());

            fail("should not be here");
        } catch (Exception e) {

            assertTrue(e instanceof UnsupportedOperationException);
        }
    }
    
    @Test
    public void saveUserWithPowerMock() {
        UserDao uDao = PowerMockito.mock(UserDao.class);
        User user = new User();
        PowerMockito.doNothing().when(uDao).saveUser(user);
        UserService userService = new UserService(uDao);
        userService.saveUser(user);
        Mockito.verify(uDao).saveUser(user);
    }
}

4. 🌵Mock局部变量的详细讲解

4.1 局部变量类方法

public class UserService {

    public int getUserCount() {

        UserDao userDao = new UserDao();

        return userDao.getUserCount();
    }

    public void saveUser(User user) {
        UserDao userDao = new UserDao();
        
        userDao.saveUser(user);
    }
}

4.2. 单元测试

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({UserService.class})
public class UserServiceTest {

    @Test
    public void getUserCount() {
        try {

            User user = new User();
            UserService userService = new UserService();
            UserDao userDao = PowerMockito.mock(UserDao.class);
            PowerMockito.whenNew(UserDao.class).withAnyArguments().thenReturn(userDao);
            PowerMockito.doNothing().when(userDao).saveUser(user);

            userService.saveUser(user);

            Mockito.verify(userDao, Mockito.timeout(1)).saveUser(user);

        } catch (Throwable e) {
            fail();
        }
    }

    @Test
    public void saveUser() {
        try {

            User user = new User();
            UserService userService = new UserService();
            UserDao userDao = PowerMockito.mock(UserDao.class);
            PowerMockito.whenNew(UserDao.class).withAnyArguments().thenReturn(userDao);
            PowerMockito.doReturn(10).when(userDao).getUserCount();

            int userCount = userService.getUserCount();
            assertEquals(userCount, 10);

            Mockito.verify(userDao, Mockito.timeout(1)).getUserCount();

        } catch (Throwable e) {
            fail();
        }
    }
}

5. 📔Mock 静态方法

5.1 静态方法类

public class UserDao {

    public static int getUserCount() {

        throw new UnsupportedOperationException();
    }

    public static void saveUser( User user) {

        throw new UnsupportedOperationException();
    }
}

5.2 单元测试

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 static org.junit.Assert.*;

@RunWith(PowerMockRunner.class)
@PrepareForTest({UserService.class,UserDao.class})
public class UserServiceTest {

    @Test
    public void getUserCount() {

        try {
            PowerMockito.mockStatic(UserDao.class);
            PowerMockito.when(UserDao.getUserCount()).thenReturn(10);
            UserService userService = new UserService();
            int userCount = userService.getUserCount();
            assertEquals(10, userCount);
        } catch (Throwable e) {
            fail();
        }
    }

    @Test
    public void saveUser() {
        try {
            PowerMockito.mockStatic(UserDao.class);
            PowerMockito.doNothing().when(UserDao.class);
            UserService userService = new UserService();
            User user = new User();
            userService.saveUser(user);
            PowerMockito.verifyStatic();
        } catch (Throwable e) {
            fail();
        }
    }
}

6. 📕final修饰的类

6.1 final 方法类

final public class UserDao {

    public int getUserCount() {

        throw new UnsupportedOperationException();
    }

    public void saveUser( User user) {

        throw new UnsupportedOperationException();
    }
}

6. 2 单元测试类

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({UserService.class, UserDao.class})
public class UserServiceTest {

    @Test
    public void saveUserWithPowerMock() {

        UserDao uDao = PowerMockito.mock(UserDao.class);
        User user = new User();
        PowerMockito.doNothing().when(uDao).saveUser(user);
        UserService userService = new UserService(uDao);
        userService.saveUser(user);
        Mockito.verify(uDao).saveUser(user);
    }
}

7. 📗verify的使用

7.1 verify service 类

public class UserDao {

    public  int getUserCount(User user) {

        throw new UnsupportedOperationException();
    }

    public  void saveUser( User user) {

        throw new UnsupportedOperationException();
    }

    public void updateUser(User user) {

        throw new UnsupportedOperationException();
    }
}
public class UserService {

    public void saveOrUpdate(User user) {
        UserDao userDao = new UserDao();

        if (userDao.getUserCount(user) > 0) {
            userDao.updateUser(user);
        } else {
            userDao.saveUser(user);
        }
    }
}

7.2 单元测试类

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({UserService.class})
public class UserServiceTest {

    @Test
    public void saveOrUpdate() throws Exception {

        User user = PowerMockito.mock(User.class);

        UserDao userDao = PowerMockito.mock(UserDao.class);

        PowerMockito.whenNew(UserDao.class).withAnyArguments().thenReturn(userDao);

        //    PowerMockito.when(userDao.getUserCount(user)).thenReturn(0);
        PowerMockito.when(userDao.getUserCount(user)).thenReturn(1);

        UserService userService = new UserService();

        userService.saveOrUpdate(user);

        // 更新上面的return 值判断走哪条线路
//        Mockito.verify(userDao, Mockito.never()).updateUser(user);
//        Mockito.verify(userDao).saveUser(user);

        Mockito.verify(userDao).updateUser(user);
        Mockito.verify(userDao, Mockito.never()).saveUser(user);
    }
}

8. 📘Mock 构造函数的使用

8.1 构造类

public class UserDao {

    private String name;

    private Integer age;

    public UserDao(String name, Integer age) {
        this.name = name;
        this.age = age;
    }
    public int saveUser () {

        throw  new UnsupportedOperationException();
    }
}
public class UserService {

    public void saveUser(String name, Integer age) {
        UserDao userDao = new UserDao(name, age);
        userDao.saveUser();
    }
}

8.2 单元测试类

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({UserService.class})
public class UserServiceTest {

    @Test
    public void saveUser() throws Exception {
        UserDao userDao = PowerMockito.mock(UserDao.class);
        String name = "zhangsan";
        Integer age = 10;
        PowerMockito.whenNew(UserDao.class).withArguments(name, age).thenReturn(userDao);

        UserService userService = new UserService();
        userService.saveUser(name, age);

        Mockito.verify(userDao).saveUser();
    }
}

9. ✂️ArgumentsMather 的使用

9.1 单元类方法

public class UserDao {
    public String getName(String name) {
        throw new UnsupportedOperationException();
    }
}
public class UserService {
    public String find(String name) {
        UserDao userDao = new UserDao();
        return userDao.getName(name);
    }
}

9.2 单元测试

import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.ArgumentMatcher;
import org.mockito.Matchers;
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({UserService.class})
public class UserServiceTest {

    @Test
    public void find() throws Exception {

        UserDao userDao = PowerMockito.mock(UserDao.class);

        PowerMockito.whenNew(UserDao.class).withAnyArguments().thenReturn(userDao);
        UserService userService = new UserService();

        PowerMockito.when(userDao.getName("alex")).thenReturn("zhangsan");
        String result = userService.find("alex");
        assertEquals(result, "zhangsan");

        PowerMockito.when(userDao.getName("wuhan")).thenReturn("liming");
        String result1 = userService.find("wuhan");
        assertEquals(result1, "liming");
    }

    // 不同参数返回同一个结果
    @Test
    public void findWithMatcher() throws Exception {

        UserDao userDao = PowerMockito.mock(UserDao.class);

        PowerMockito.whenNew(UserDao.class).withAnyArguments().thenReturn(userDao);
        UserService userService = new UserService();

        PowerMockito.when(userDao.getName(Matchers.argThat(new MyArguments()))).thenReturn("zhangsan");
        assertEquals("zhangsan", userService.find("alex"));
        assertEquals("zhangsan", userService.find("wuhan"));

    }


    static class MyArguments extends ArgumentMatcher<String> {

        @Override
        public boolean matches(Object o) {
            String arg = (String)o;

            switch (arg){
                case "alex":
                case "wuhan":
                    return true;
                default:
                    return false;
            }
        }
    }
}

10 📌Answer 不同参数返回不同结果

@Test
    public void findWithAnswer() throws Exception {

        UserDao userDao = PowerMockito.mock(UserDao.class);

        PowerMockito.whenNew(UserDao.class).withAnyArguments().thenReturn(userDao);
        UserService userService = new UserService();

        PowerMockito.when(userDao.getName(Mockito.anyString())).then( param -> {
           String result =  (String) param.getArguments()[0];
           switch (result){
               case "zhangsan":
                   return "I am zhangsan";
               case "lisi":
                   return "I am lisi";
               default:
                   throw new RuntimeException();
           }
        });


        assertEquals("I am zhangsan", userService.find("zhangsan"));
        assertEquals("I am lisi", userService.find("lisi"));

        try {
            assertEquals("I am zhangsan", userService.find("zhangsan1"));
        } catch (Exception e) {
            assertTrue(e instanceof  RuntimeException);
        }
    }

11. 🍄Spy使用

11.1 spy 单元类

public class UserService {


    public void findLog(String name) {

        log();
    }

    private void log() {

        System.out.println("this is log");
    }
}

11.2 单元测试

public class UserServiceTest {

    @Test
    public void findLog() {
        UserService userService = new UserService();
        userService.findLog("11");
    }

    @Test
    public void findLogWithPowerMock() {
        UserService userService = PowerMockito.mock(UserService.class);
        userService.findLog("111");
    }

    @Test
    public void findLogWithPowerSpy() {
        UserService userService = PowerMockito.spy(new UserService());
        String arg = "zhangsan";

        // 符合断言不会走真正的逻辑
        PowerMockito.doNothing().when(userService).findLog(arg);
        userService.findLog(arg);
    }
}

说明:

采用spy方式mock一个对象,然后调用其中的某个方法,他会根据真实的class 所提供的方法来调用

12 🌾私有方法的Mock

12.1 单元类

public class MockPrivateService {

    private String name;
    private Integer age;
    public void sendInf() {

        System.out.println("my name is " + name + ", age : " + age);
    }
}

12.2 单元测试类

import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.InjectMocks;
import org.powermock.api.mockito.PowerMockito;
import org.powermock.core.classloader.annotations.PrepareForTest;
import org.powermock.modules.junit4.PowerMockRunner;


@RunWith(PowerMockRunner.class)
@PrepareForTest({MockPrivateService.class})
public class MockPrivateServiceTest {
    @InjectMocks
    private MockPrivateService mockPrivateService;

    @Test
    public void sendInf () throws Exception {

//        MockPrivateService mockPrivateService = PowerMockito.mock(MockPrivateService.class);
//
//        PowerMockito.whenNew(MockPrivateService.class).withAnyArguments().thenReturn(mockPrivateService);
        PowerMockito.field(MockPrivateService.class, "name").set(mockPrivateService, "zhangsan");
        PowerMockito.field(MockPrivateService.class, "age").set(mockPrivateService, 10);

        mockPrivateService.sendInf();
    }
}

🌵附件

代码参考