现如今比较流行的Mock工具如jMock、EasyMock 、Mockito等都有一个共同的缺点:不能mock静态、final、私有方法等。而PowerMock能够完美的弥补以上三个Mock工具的不足。
PowerMock是一个扩展了其它如EasyMock等mock框架的、功能更加强大的框架。PowerMock使用一个自定义类加载器和字节码操作来模拟静态方法,构造函数,final类和方法,私有方法,去除静态初始化器等等。通过使用自定义的类加载器,简化采用的IDE或持续集成服务器不需要做任何改变。熟悉PowerMock支持的mock框架的开发人员会发现PowerMock很容易使用,因为对于静态方法和构造器来说,整个的期望API是一样的。PowerMock旨在用少量的方法和注解扩展现有的API来实现额外的功能。目前PowerMock支持EasyMock和Mockito。
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);
}
}
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);
}
}
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);
}
}
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();
}
}
}
public class UserDao {
public static int getUserCount() {
throw new UnsupportedOperationException();
}
public static void saveUser( User user) {
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 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();
}
}
}
final public class UserDao {
public int getUserCount() {
throw new UnsupportedOperationException();
}
public void saveUser( User user) {
throw new UnsupportedOperationException();
}
}
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);
}
}
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);
}
}
}
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);
}
}
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();
}
}
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();
}
}
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);
}
}
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;
}
}
}
}
@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);
}
}
public class UserService {
public void findLog(String name) {
log();
}
private void log() {
System.out.println("this is log");
}
}
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 所提供的方法来调用
public class MockPrivateService {
private String name;
private Integer age;
public void sendInf() {
System.out.println("my name is " + name + ", age : " + age);
}
}
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();
}
}
代码参考