阅读本篇博客前建议有Mockito基础,参见上一篇文章:单元测试系统化讲解之Mockito
本次讲解的PowerMock是单元测试的进阶技术框架;所以学习PowerMock中,博主假设你们已经满足如下条件:
PowerMock是什么?
PowerMock解决了哪些痛点?
new 出来的对象注意:为什么总说PowerMock尽量少用?
PowerMock有两个重要的注解,分别是:
@RunWith(PowerMockRunner.class)
@PrepareForTest( { YourClassWithEgStaticMethod.class })
使用了@PrepareForTest注解,能够使用PowerMock的强大功能(mock静态、final、私有方法等);需要注意的是,它不能单独生效,我们必须要同时加上@RunWith(PowerMockRunner.class)
使用PowerMock的依赖项:
<dependency>
<groupId>org.powermock</groupId>
<artifactId>powermock-module-junit4</artifactId>
<version>1.6.5</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.powermock</groupId>
<artifactId>powermock-api-mockito</artifactId>
<version>1.6.5</version>
<scope>test</scope>
</dependency>
开始测试:
编写被测试的类:
public class UserService{
private UserDao userDao;
public UserService(UserDao userDao){
this.userDao = userDao;
}
public int querUserCount(){
return userDao.getCount();
}
public void saveUser(User user){
userDao.insertUser(user);
}
}
测试类:
public class UserServiceTest{
private UserService userService;
@Before
public void setUp(){
userService = new UserService(new UserDao());
}
@Mock
private UserDao userDao;
@Test
public void testQueryUserCountWithPowerMock(){
UserDao uDao = PowerMockito.mock(UserDao.class);
PowerMockito.when(uDao.getCount()).thenReturn(10);
UserService service = new UserService(uDao);
int result = service.queryUserCount();
assertEquals(10,result);
}
@Test
public void testQueryUserCountWithMockito(){
MockitoAnnotations.initMocks(this);
UserService service = new UserService(userDao);
Mockito.when(userDao.getCount()).thenReturn(10);
int result = service.queryUserCount();
assertEquals(10,result);
}
@Test
public void testSaveUserWIthJunit(){
try{
userService.saveUser(new User());
fail("should not process to here");
}catch (Exception e){
assertTrue(e instanceof UnsupportedOperationException);
}
}
}
代码中展示了Junit、mockito、powermock的三种测试方式。
public class UserService{
public int queryUserCount(){
UserDao userDao = new UserDao();
return userDao.getCount();
}
public void saveUser(User user){
UserDao userDao = new userDao();
userDao.insertUser(user);
}
}
@RunWith(PowerMockRunner.class)
@PrepareForTest(UserService.class)
public class UserServiceTest{
@Test
public void tesetQueryUserCount(){
try{
UserService userService = new UserService();
UserDao userDao = mock(UserDao.class);
whenNew(UserDao.class).withNoArguments().thenReturn(userDao);
doReturn(10).when(userDao).getCount();
int result = userService.queryUserCount();
assertEquals(10,result);
}catch(Throwable e){
fail();
}
}
@Test
public void testSaveUser(){
try{
User user = new User();
UserService userService = new UserService();
UserDao userDao = mock(UserDao.class);
whenNew(UserDao.class).withAnyArguments().thenReturn(userDao);
userService.saveUser(user);
Mockito.verify(userDao,Mockito.times(1)).insertUser(user);
}catch(Throwable e){
fail();
}
}
}
public class UserDao{
public static int getCount(){
throw new UnsupportedOperationException();
}
public static void insertUser(User user){
throw new UnsupportedOperationException();
}
}
public class UserService{
public int queryUserCount(){
return UserDao.getCount();
}
public void saveUser(User user){
UserDao userDao = new UserDao();
UserDao.insertUser(user);
}
}
@RunWith(PowerMockRunner.class)
@PrepareForTest({UserService.class,UserDao.class})
public class UserServiceTest{
@Test
public void testQueryUserCount() throws Exception{
PowerMockito.mockStatic(UserDao.class);
PowerMockito.when(UserDao.getCount()).thenReturn(10);
UserService userService = new UserService();
int result = userService.queryUserCount();
assertEquals(10,result);
}
@Test
public void testSaveUser() throws Exception{
mockStatic(UserDao.class);
User user = new User();
doNoting().when(UserDao.class);
UserService userService = new UserService();
userService.saveUser(user);
PowerMockito.verifyStatic();
}
}
final 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 suer){
userDao.insertUser(user);
}
}
@RunWith(PowerMockRunner.class)
@PrepareForTest({UserService.class,UserDao.class})
public class UserServiceTest{
@Test
public void testQueryUserCountWithPowerMock() throws Exception{
UserDao uDao = PowerMockito.mock(UserDao.class);
System.out.println(uDao.getClass());
PowerMockito.when(uDao.getCount()).thenReturn(10);
UserService userService = new UserService(uDao);
int result = userService.queryUserCount();
assertEquals(10,result);
}
}
public class UserDao{
public int getCount(User user){
throw new UnsupportedOperationException();
}
public void updateUser(User user){
throw new UnsupportedOperationException();
}
public void insertUser(User user){
throw new UnsupportedOperationException();
}
}
public class UserService{
public void saveOrUpdate(User user){
UserDao userDao = new UserDao();
if(userDao.getCount(user) > 0){
userDao.updateUser(user);
}else{
userDao.insertUser(user);
}
}
}
@RunWith(PowerMockRunner.class)
@PrepareForTest(UserService.class)
public class UserSErviceTest{
@Test
public void testSaveOrUpdateWillUseNewJoiner() throw Exception {
User user = PowerMockito.mock(User.class);
UserDao userDao = PowerMockito.mock(UserDao.class);
PowerMockito.whenNew(UserDao.class).withAnyArguments().thenReturn(user);
PowerMockito.when(userDao.getCount(user)).thenReturn(0);
UserService userService = new UserService();
userService.saveOrUpdate(user);
}
@Test
public void testSaveOrUpdateWillUseUpdateOriginal() throw Exception{
User user = PowerMockito.mock(User.class);
UserDao userDao = PowerMockito.mock(userDao.class);
PowerMockito.whenNew(UserDao.class).withAnyArguments().thenRetuurn(userDao);
PowerMockito.when(userDao.getCount(user)).thenReturn(1);
UserService userService = new UserService();
userService.saveOrUpdate(user);
Mockito.verify(userDao).insertUser(user);
Mockito.verify(userDao,Mockito.never()).updateUser(user); // never表示一次都不会执行
}
}
verify有很多方法,同学们可以看看源码或者官方文档来进行使用和练习;
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();
}
}
@RunWith(PowerMockRunner.class)
@PrepareForTest(UserService.class)
public class UserServiceTest{
@Test
public void testSave() throws Exception(){
UserDao userDao = PowerMockito.mock(UserDao.class);
String username = "anyu";
String passsword = "lyle";
PowerMocktio.whenNew(UserDao.class).withArguments(username,passsword).thenReturn(userDao);
PowerMockito.doNoting().when(userDao).insert();
UserService userService = new UserService();
Mockito.verify(userDao).insert();
}
}
public class UserDao{
public String queryByName(String username){
throw new UnsupportedOperationException();
}
}
public class UserService{
public String find(String name){
UserDao userDao = new UserDao();
return userDao.queryByName(name);
}
}
@RunWith(PowerMockRunner.class)
@PrepareForTest(UserService.class)
public class UserServiceTest{
@Test
public void testFind() throws Exception{
UserDao userDao = PowerMockito.mock(UserDao.class);
PowerMockito.whenNew(UserDao.class).withAnyArguments().thenReturn(userDao);
PowerMockito.when(userDao.queryByName("lyle")).thenReturn("anyu");
UserService service= UserService();
String result = service.find("lyle");
assertEquals("anyu",result);
PowerMockito.when(userDao.queryByName("Jacky")).thenReturn("anyu");
UserService service= UserService();
String result = service.find("lyle");
assertEquals("anyu",result);
PowerMockito.when(userDao.queryByName("Tommy")).thenReturn("anyu");
UserService service= UserService();
String result = service.find("lyle");
assertEquals("anyu",result);
}
// 使用match
@Test
public void testFindWithMatcher() throw Exception{
UserDao userDao = PowerMockito.mock(UserDao.class);
PowerMockito.whenNew(UserDao.class).withAnyArguments().thenReturn(userDao); //CSDN:暗余
PowerMockito.when(userDao.queryByName(Matchers.argThat(new MyArgumentMatcher()))).thenReturn("anyu");
UserService service = new UserService();
assertEquals("lyle",service.find("lyle"));
assertEquals("lyle",service.find("Jacky"));
assertEquals("lyle",service.find("Van"));
assertEquals("lyle",service.find("Tony"));
}
static class MyargumentMatcher extends ArgumentMatcher<String>{
@Override
public boolean matches(Object o){
String arg = (String) o;
switch(arg){
case "lyle":
case "Jacky":
case "Van":
case "Tony":
return true;
default:
return false;
}
}
}
}
public class UserDao{
public String queryByName(String username){
throw new UnsupportedOperationException();
}
}
public class UserService{
public String find(String name){
UserDao userDao = new UserDao();
return userDao.queryByName(name);
}
}
@RunWith(PowerMockRunner.class)
@PrepareForTest(UserService.class)
public class UserServiceTest{
@Test
public void testFindWithAnswer() throw Exception{
UserDao userDao = PowerMockito.mock(UserDao.class);
PowerMockito.whenNew(UserDao.class).withAnyArguments().thenReturn(userDao);
PowerMockito.when(userDao.queryByName(Mockito.anyString())).then(invocation -> {
String arg = (String) invocation.getArguments()[0];
switch(arg){
case "lyle":
return "I am csdn 暗余";
case "Alex":
return "I am alex";
default:
throw new RuntimeException("Not support "+ arg);
}
});
UserService service = new UserService();
assertEquals("I am casn 暗余",service.find("lyle"));
assertEquals("I am alex", service.find("Alex"));
}
}
public class UserService{
public void foo(){
log();
}
private void log(){
System.out.println("I am console log.");
}
public boolean exist(String username){
return checkExist(username);
}
private boolean checkExist(String username){
throw new UnsupportedOperationException();
}
}
使用spy会调用真实的方法:

如果使用了when函数指定了对应方法的请求参数,当传入对应的请求参数时会调用mock的方法不会打印任何内容;

而不满足条件,则会继续执行真实的方法:

测试私有方法:
public class UserServiceTest{
@Test
public void testCheck() throws Exception{
UserService userService = PowerMockito.apy(new UserService());
PowerMockito.doReturn(true).when(userService,"checkExist","lyle");
assertTrue(userService.exist("lyle"));
// 这个参数没有被定义,所以会走本身的方法,即触发异常
userService.exist("other");
}
}
写文不易,觉得不错点个赞再走吧~ ^^