PowerMock

A unit test should exhibit the following characteristics.

  • It should be automated.
  • It should have a fast test execution.
  • A test should not depend on the result of another test or rather test execution order. Unit test framework can execution tests in any order.
  • A test should not depend on database access, file storage, or any long running task. Rather, an appropriate test double should isolate the external dependencies.
  • A test result should be consistent and time-and-location transparent.
  • Tests should be meaningful.
  • Tests should be short and tests should not be treated as second-class citizens.

1.Mock变量

1).类属性

public class UserDao {
    public int getCount(){
        throw new UnsupportedOperationException();
    }
	
    public void insertUser(User user) {
        throw new UnsupportedOperationException();
    }
}
public class UserService {
    private UserDao userDao;

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

    public int queryUserCount(){
        return userDao.getCount();
    }

    public void saveUser(User user){
        userDao.insertUser(user);
    }
}
import heju.powermock.dao.UserDao;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.mockito.Mockito;
import org.powermock.api.mockito.PowerMockito;

import static org.junit.Assert.*;
import static org.mockito.Mockito.reset;
import static org.mockito.Mockito.times;

public class UserServiceTest {
    private UserDao userDao;
    private UserService userService;

    @Before
    public void setUp() {
        userDao = PowerMockito.mock(UserDao.class);
        userService = new UserService(userDao);
    }

    @Test
    public void queryUserCount() {
        PowerMockito.doReturn(10).when(userDao).getCount();
        int count = userService.queryUserCount();
        assertEquals(10, count);
    }

    @Test
    public void saveUser() {
        User user = PowerMockito.mock(User.class);
        PowerMockito.doNothing().when(userDao).insertUser(user);
        userService.saveUser(user);
        Mockito.verify(userDao).insertUser(user);
    }
    
    @After
    public void destroy(){
        reset(userDao);
        reset(userService);
    }
}

2).局部变量whenNew…then…

public class UserService {
    public int queryUserCount(){
        UserDao useDao = new UserDao();
        return useDao.getCount();
    }

    public void saveUser(User user){
        UserDao useDao = new UserDao();
        useDao.insertUser(user);
    }
}
import heju.powermock.dao.UserDao;
import org.junit.After;
import org.junit.Before;
import org.junit.Ignore;
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.assertEquals;
import static org.junit.Assert.fail;
import static org.mockito.Mockito.reset;
import static org.mockito.Mockito.verify;
import static org.powermock.api.mockito.PowerMockito.*;

@RunWith(PowerMockRunner.class)
@PrepareForTest(UserService2.class)
public class UserService2Test {
    private UserService2 userService;

    private UserDao userDao;

    @Before
    public void setUp(){
        userService = new UserService2();
        userDao = mock(UserDao.class);
    }

    @Test
    public void queryUserCount() {
        try {
            whenNew(UserDao.class).withNoArguments().thenReturn(userDao);
            doReturn(10).when(userDao).getCount();
            int count = userService.queryUserCount();
            assertEquals(10, count);
        } catch (Exception e) {
            fail();
        }
    }

    @Test
    public void saveUser() {
        try {
            User user = mock(User.class);
            whenNew(UserDao.class).withAnyArguments().thenReturn(userDao);
//            whenNew(UserDao.class).withNoArguments().thenReturn(userDao);
            doNothing().when(userDao).insertUser(user);
            userService.saveUser(user);
            verify(userDao).insertUser(user);
        } catch (Exception e) {
            fail();
        }
    }

    @After
    public void destroy(){
        reset(userDao);
        reset(user);
    }
}

2.Mock静态方法

mockStatic

public class User {
}
import heju.powermock.service.User;


public class UserDao {
    public static int getCount(){
        throw new UnsupportedOperationException();
    }

    public static void insertUser(User user) {
        throw new UnsupportedOperationException();
    }
}
import heju.powermock.dao.UserDao;

public class UserService {
    public int queryUserCount(){
        return UserDao.getCount();
    }

    public void saveUser(User user){
        UserDao.insertUser(user);
    }
}

import heju.powermock.dao.UserDao;
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.assertEquals;
import static org.powermock.api.mockito.PowerMockito.*;

@RunWith(PowerMockRunner.class)
@PrepareForTest({UserService.class, UserDao.class})
public class UserServiceTest {
    @Test
    public void queryUserCount() {
        mockStatic(UserDao.class);
        UserService userService = new UserService();
        when(UserDao.getCount()).thenReturn(10);
        int count = userService.queryUserCount();
        assertEquals(10, count);
    }

    @Test
    public void saveUser() throws Exception {
        User user = new User();
        mockStatic(UserDao.class);
        doNothing().when(UserDao.class);
        UserService userService = new UserService();
        userService.saveUser(user);
        // 此处报错,暂未解决
        verifyStatic(UserDao.class);
    }
}

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-oPu3VAZF-1642946215902)(/home/heju/.config/Typora/typora-user-images/image-20211228200042139.png)]

3.Mock final

final修饰的class和method

@PrepareForTest({finalClass.class})注解中加入final对应的class即可

public final class UserDao {
    public int getCount(){
        throw new UnsupportedOperationException();
    }

    public final void insertUser(User user) {
        throw new UnsupportedOperationException(); 
    }
}
import heju.powermock.dao.UserDao;

public class UserService {
    private UserDao userDao;

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

    public int queryUserCount(){
        return userDao.getCount();
    }

    public void saveUser(User user){
        userDao.insertUser(user);
    }
}
import heju.powermock.dao.UserDao;
import org.junit.After;
import org.junit.Before;
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.mockito.Mockito.*;
import static org.powermock.api.mockito.PowerMockito.mock;
import static org.powermock.api.mockito.PowerMockito.when;

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

    private UserService userService;

    @Before
    public void setUp() {
        userDao = mock(UserDao.class);
        userService = new UserService(userDao);
    }

    @Test
    public void queryUserCount() {
        when(userDao.getCount()).thenReturn(10);
        int count = userService.queryUserCount();
        assertEquals(10, count);
    }

    @Test
    public void saveUser() {
        User user = mock(User.class);
        doNothing().when(userDao).insertUser(user);
        userService.saveUser(user);
        verify(userDao).insertUser(user);
    }

    @After
    public void tearDown() {
        reset(userDao);
    }
}

4.spy与Mock私有方法

public class UserService {
    public void foo(String str){
        log();
    }

    private void log(){
        System.out.println("log info");
    }

    public boolean check(String arg){
        return exists(arg);
    }

    private boolean exists(String arg) {
        throw new UnsupportedOperationException();
    }
}
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 org.powermock.reflect.Whitebox;

import static org.junit.Assert.*;

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

    @Test
    public void foo() throws Exception {
        UserService userService = PowerMockito.spy(new UserService());
        String arg = "hello";
        PowerMockito.doNothing().when(userService).foo(arg);
        // 不调用真实方法
        userService.foo(arg);
        // 调用真实方法
        userService.foo("");

        Whitebox.invokeMethod(userService, "log");
        PowerMockito.verifyPrivate(userService).invoke("log");
    }

    @Test
    public void check() throws Exception {
        UserService userService = PowerMockito.spy(new UserService());
        PowerMockito.doReturn(true).when(userService, "exists", "alex");
        assertTrue(userService.check("alex"));
        try {
            assertTrue(userService.check("connie"));
        }catch (Exception e){
            assertTrue(e instanceof UnsupportedOperationException);
        }
    }
}

5.verify的使用

import heju.powermock.service.User;


public class UserDao {
    public int getCount(User user){
        throw new UnsupportedOperationException();
    }

    public void insertUser(User user) {
        throw new UnsupportedOperationException();
    }

    public void updateUser(User user) {
        throw new UnsupportedOperationException();
    }
}
import heju.powermock.dao.UserDao;

public class UserService {

    public void saveUser(User user){
        UserDao userDao = new UserDao();
        if (userDao.getCount(user) > 0){
            userDao.updateUser(user);
        }else{
            userDao.insertUser(user);
        }
    }
}
import heju.powermock.dao.UserDao;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mockito;
import org.powermock.core.classloader.annotations.PrepareForTest;
import org.powermock.modules.junit4.PowerMockRunner;

import static org.mockito.Mockito.reset;
import static org.powermock.api.mockito.PowerMockito.*;

@RunWith(PowerMockRunner.class)
@PrepareForTest(UserService.class)
public class UserServiceTest {
    private User user;
    private UserDao userDao;

    @Before
    public void setUp() throws Exception {
        user = mock(User.class);
        userDao = mock(UserDao.class);
        whenNew(UserDao.class).withNoArguments().thenReturn(userDao);
    }

    @Test
    public void saveUser_Insert() {
        when(userDao.getCount(user)).thenReturn(0);
        UserService userService = new UserService();
        userService.saveUser(user);
        Mockito.verify(userDao).insertUser(user);
        Mockito.verify(userDao, Mockito.never()).updateUser(user);
    }

    @Test
    public void saveUser_Update() {
        when(userDao.getCount(user)).thenReturn(1);
        UserService userService = new UserService();
        userService.saveUser(user);
        Mockito.verify(userDao, Mockito.never()).insertUser(user);
        Mockito.verify(userDao).updateUser(user);
    }

    @After
    public void tearDown(){
        reset(user);
        reset(userDao);
    }
}

6.Mock不同的构造函数

1).whenNew…withArguments

2).whenNew…withNoArguments

3).whenNew…withAnyArguments

public class UserDao {
    private String username;
    private String password;

    public UserDao(String username, String password) {
        this.username = username;
        this.password = password;
    }

    public void insert(){
        throw new UnsupportedOperationException();
    }
}
public class UserService {
    public void save(String username, String password){
        UserDao userDao = new UserDao(username, password);
        userDao.insert();
    }
}
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 save() throws Exception {
        UserDao userDao = PowerMockito.mock(UserDao.class);
        String username = "heju";
        String password = "123";
        PowerMockito.whenNew(UserDao.class).withArguments(username, password).thenReturn(userDao);
        PowerMockito.doNothing().when(userDao).insert();
        UserService userService = new UserService();
        userService.save(username, password);
        Mockito.verify(userDao).insert();
    }
}

7.ArgumentMatcher接口的使用

when…then不同参数返回相同值时使用

public class UserDao {

    public String queryByName(String name) {
        throw new UnsupportedOperationException();
    }
}
public class UserService {
    public String query(String name){
        UserDao userDao = new UserDao();
        return userDao.queryByName(name);
    }
}
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.ArgumentMatcher;
import org.powermock.api.mockito.PowerMockito;
import org.powermock.core.classloader.annotations.PrepareForTest;
import org.powermock.modules.junit4.PowerMockRunner;

import static org.junit.Assert.assertEquals;
import static org.mockito.ArgumentMatchers.argThat;
import static org.mockito.Mockito.reset;
import static org.powermock.api.mockito.PowerMockito.when;
import static org.powermock.api.mockito.PowerMockito.whenNew;

@RunWith(PowerMockRunner.class)
@PrepareForTest(UserService.class)
public class UserServiceTest {
    private UserDao userDao;
    private UserService userService;

    @Before
    public void setUp() throws Exception {
        userDao = PowerMockito.mock(UserDao.class);
        whenNew(UserDao.class).withNoArguments().thenReturn(userDao);
        userService = new UserService();
    }

    @Test
    public void queryWithStub() {
        when(userDao.queryByName("jack")).thenReturn("vip");
        String name = userService.query("jack");
        assertEquals("vip", name);

        when(userDao.queryByName("alex")).thenReturn("vip");
        name = userService.query("alex");
        assertEquals("vip", name);

        when(userDao.queryByName("connie")).thenReturn("vip");
        name = userService.query("connie");
        assertEquals("vip", name);
    }

    @Test
    public void queryWithMatcher(){
        when(userDao.queryByName(argThat(new myArgumentMatcher()))).thenReturn("vip");
        assertEquals("vip", userService.query("jack"));
        assertEquals("vip", userService.query("alex"));
        assertEquals("vip", userService.query("connie"));
    }

    private static class myArgumentMatcher implements ArgumentMatcher<String> {
        @Override
        public boolean matches(String s) {
            switch (s){
                case "jack":
                case "alex":
                case "connie":
                    return true;
                default:
                    return false;
            }
        }
    }

    @After
    public void tearDown(){
        reset(userDao);
    }
}

8.Answer接口的使用

when…then不同参数返回不同值

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

import static org.junit.Assert.assertEquals;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.Mockito.reset;
import static org.powermock.api.mockito.PowerMockito.when;
import static org.powermock.api.mockito.PowerMockito.whenNew;

@RunWith(PowerMockRunner.class)
@PrepareForTest(UserService.class)
public class UserServiceTest {
    private UserDao userDao;
    private UserService userService;

    @Before
    public void setUp() throws Exception {
        userDao = PowerMockito.mock(UserDao.class);
        whenNew(UserDao.class).withNoArguments().thenReturn(userDao);
        userService = new UserService();
    }

    @Test
    public void queryWithAnswer(){
        when(userDao.queryByName(anyString())).then(invocation -> {
            String argument = (String) invocation.getArguments()[0];
            switch (argument){
                case "jack":
                    return "svip";
                case "alex":
                    return "vip";
                case "connie":
                    return "black";
                default:
                    return "active user";
            }
        });
        assertEquals("svip", userService.query("jack"));
        assertEquals("vip", userService.query("alex"));
        assertEquals("black", userService.query("connie"));
        assertEquals("active user", userService.query("monica"));
    }
    
    @After
    public void tearDown(){
        reset(userDao);
    }
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值