最近项目中单元测试覆盖率要求越来越高,之前Junit和Mock已经无法胜任,所以引入了更强大的PowerMock,方便我们解决静态方法,私有方法等。因此,本文输出PowerMock作为实际使用的小结。
maven项目引入依赖(版本号看实际需要)
1 <dependency> 2 <groupId>org.powermock</groupId> 3 <artifactId>powermock-module-junit4</artifactId> 4 <version>${powermock.version}</version> 5 <scope>test</scope> 6 </dependency> 7 <dependency> 8 <groupId>org.powermock</groupId> 9 <artifactId>powermock-api-mockito</artifactId> 10 <version>${powermock.version}</version> 11 <scope>test</scope> 12 </dependency>
普通POJO
public class User { private String name; private String password; }
普通Dao
1 public class UserDao { 2 3 public int getCount(){ 4 throw new UnsupportedOperationException(); 5 } 6 7 public void saveUser(User user){ 8 throw new UnsupportedOperationException(); 9 } 10 11 /** 12 * 静态方法 13 */ 14 public static int removeUser(User user){ 15 throw new UnsupportedOperationException(); 16 } 17 18 }
普通Service
1 public class UserService { 2 3 private UserDao userDao; 4 5 public UserService(UserDao userDao) { 6 this.userDao = userDao; 7 } 8 9 public int getUserCount() { 10 return userDao.getCount(); 11 } 12 13 public void saveUser(User user) { 14 userDao.saveUser(user); 15 } 16 17 /** 18 * 调用了静态方法 19 */ 20 public int removeUser(User user) { 21 return UserDao.removeUser(user); 22 } 23 24 }
一、针对普通方法的测试
(1)有参返回——Mock和PowerMock都能处理
1 public class UserServiceTest { 2 3 @Test 4 public void getUserCountwithMockito() { 5 UserDao userDao = Mockito.mock(UserDao.class); 6 Mockito.when(userDao.getCount()).thenReturn(10); 7 UserService userService = new UserService(userDao); 8 int resutl = userService.getUserCount(); 9 Assert.assertEquals(10, resutl); 10 Mockito.verify(userDao, Mockito.times(1)).getCount(); 11 } 12 13 @Test 14 public void getUserCountwithPowerMockito() { 15 UserDao userDao = PowerMockito.mock(UserDao.class); 16 PowerMockito.when(userDao.getCount()).thenReturn(5); 17 UserService userService = new UserService(userDao); 18 int resutl = userService.getUserCount(); 19 Assert.assertEquals(5, resutl); 20 } 21 22 }
(2)无参返回——Mock和PowerMock都能处理
1 public class UserServiceTest { 2 3 @Test 4 public void saveUserwithMock() { 5 // User user = Mockito.mock(User.class); 6 User user = new User(); 7 UserDao userDao = Mockito.mock(UserDao.class); 8 Mockito.doNothing().when(userDao).saveUser(user); 9 UserService userSerivce = new UserService(userDao); 10 userSerivce.saveUser(user); 11 Mockito.verify(userDao, Mockito.times(1)).saveUser(user); 12 } 13 14 15 @Test 16 public void saveUserwithPowerMock() { 17 // User user = new User(); 18 User user = PowerMockito.mock(User.class); 19 UserDao userDao = PowerMockito.mock(UserDao.class); 20 PowerMockito.doNothing().when(userDao).saveUser(user); 21 UserService userService = new UserService(userDao); 22 userService.saveUser(user); 23 24 } 25 26 }
二、针对静态方法——只能用PowerMock处理了
当调用UserDao的静态方法时,通过@PrepareForTest注解提前准备好一个UserDao类。
1 @RunWith(PowerMockRunner.class) 2 @PrepareForTest({UserDao.class}) 3 public class UserServiceTest { 4 /** 5 * 处理静态方法-PowerMock,在类上添加两个注解: 7 * @RunWith(PowerMockRunner.class) 8 * @PrepareForTest(UserDao.class) 9 */ 10 @Test 11 public void removeUserwithPowerMock() { 12 User user = PowerMockito.mock(User.class); 13 PowerMockito.mockStatic(UserDao.class); 14 PowerMockito.when(UserDao.removeUser(user)).thenReturn(1); 15 UserService userService = new UserService(new UserDao()); 16 int result = userService.removeUser(user); 17 Assert.assertEquals(1, result); 18 } 19 }
三、局部变量——只能用PowerMock处理了
普通POJO
import lombok.Getter; import lombok.Setter; @Getter @Setter public class Employee { private String name; private String password; }
普通Dao
1 public class EmployeeDao { 2 3 public int getTotalCount(Employee employee) { 4 throw new UnsupportedOperationException(); 5 } 6 7 public void creatEmployee(Employee employee) { 8 throw new UnsupportedOperationException(); 9 } 10 11 public void updateEmployee(Employee employee) { 12 throw new UnsupportedOperationException(); 13 } 14 15 public int getEmployeeCount(Employee employee) { 16 throw new UnsupportedOperationException(); 17 } 18 19 public String getEmployeeByName(String name){ 20 throw new UnsupportedOperationException(); 21 } 22 }
普通Service
1 public class EmployeeService { 2 3 /** 4 * 局部变量:内部无参构造创建对象,整个方法有返回值 5 */ 6 public int getTotalCount(Employee employee) { 7 EmployeeDao employeeDao = new EmployeeDao(); 8 return employeeDao.getTotalCount(employee); 9 } 10 /** 11 * 局部变量:内部无参构造创建对象,整个方法无返回值 12 */ 13 public void createEmployee(Employee employee) { 14 EmployeeDao employeeDao = new EmployeeDao(); 15 employeeDao.creatEmployee(employee); 16 } 17 18 /** 19 * 方法内有分支 20 */ 21 public void saveOrUpdate(Employee employee){ 22 EmployeeDao employeeDao = new EmployeeDao(); 23 int count = employeeDao.getEmployeeCount(employee); 24 if(count>0){ 25 employeeDao.updateEmployee(employee); 26 }else{ 27 employeeDao.creatEmployee(employee); 28 } 29 } 30 }
3.1 测试“有返回值”
@PrepareForTest(EmployeeService.class):让创建出来的EmployeeService实例,采用事先准备好的(@PrepareForTest帮助实现,底层通过改变字节码)。
PowerMockito.whenNew(EmployeeDao.class).withNoArguments().thenReturn(employeeDao):利用PowerMockito创建无参构造类的实例(通过mock已经准备,如PowerMockito.mock(Employee.class)
),其中 withNoArguments()会抛异常,需要try...catch处理。
构造函数说明
(1)PowerMockito.whenNew(EmployeeDao.class).withNoArguments()
(2)PowerMockito.whenNew(EmployeeDao.class).withAnyArguments()
(3)PowerMockito.whenNew(EmployeeDao.class).withArguments(Object firstArgument, Object... additionalArguments)
1 @RunWith(PowerMockRunner.class) 2 @PrepareForTest(EmployeeService.class) 3 public class EmployeeServiceTest { 4 5 /** 6 * 测试有返回值,在类上添加两个注解: 7 * 8 * @RunWith(PowerMockRunner.class) 9 * @PrepareForTest(EmployeeService.class) 10 */ 11 @Test 12 public void getTotalCountTest() { 13 Employee employee = PowerMockito.mock(Employee.class); 14 EmployeeDao employeeDao = PowerMockito.mock(EmployeeDao.class); 15 try { 16 PowerMockito.whenNew(EmployeeDao.class).withNoArguments().thenReturn(employeeDao); 17 PowerMockito.when(employeeDao.getTotalCount(employee)).thenReturn(5); 18 EmployeeService employeeService = new EmployeeService(); 19 int totalCount = employeeService.getTotalCount(employee); 20 Assert.assertEquals(5, totalCount); 21 } catch (Exception e) { 22 fail("测试失败..."); 23 } 24 } 25 }
3.2 测试无返回值
PowerMockito.doNothing().when(employeeDao).creatEmployee(employee);
1 @RunWith(PowerMockRunner.class) 2 @PrepareForTest(EmployeeService.class) 3 public class EmployeeServiceTest { 4 /** 5 * 测试无返回值,在类上添加两个注解: 6 * 7 * @RunWith(PowerMockRunner.class) 8 * @PrepareForTest(EmployeeService.class) 9 */ 10 @Test 11 public void creatEmplyeeTest() { 12 Employee employee = PowerMockito.mock(Employee.class); 13 14 EmployeeDao employeeDao = PowerMockito.mock(EmployeeDao.class); 15 try { 16 PowerMockito.whenNew(EmployeeDao.class).withNoArguments().thenReturn(employeeDao); 17 PowerMockito.doNothing().when(employeeDao).creatEmployee(employee); 18 EmployeeService employeeService = new EmployeeService(); 19 employeeService.createEmployee(employee); 20 Mockito.verify(employeeDao, Mockito.times(1)).creatEmployee(employee); 21 } catch (Exception e) { 22 fail("测试失败..."); 23 } 24 } 25 }
3.3 通过Mockito.verify验证分支
通过PowerMockito.when(employeeDao.getEmployeeCount(employee)).thenReturn(0):中thenReturn的返回值可以走向不同的分支。
1 @RunWith(PowerMockRunner.class) 2 @PrepareForTest(EmployeeService.class) 3 public class EmployeeServiceTest { 4 /** 5 * 测试分支及Mockito.verify,在类上添加两个注解: 6 * 7 * @RunWith(PowerMockRunner.class) 8 * @PrepareForTest(EmployeeService.class) 9 */ 10 @Test 11 public void saveOrUpdateTest1() { 12 Employee employee = PowerMockito.mock(Employee.class); 13 EmployeeDao employeeDao = PowerMockito.mock(EmployeeDao.class); 14 try { 15 16 PowerMockito.whenNew(EmployeeDao.class).withNoArguments().thenReturn(employeeDao); 17 PowerMockito.when(employeeDao.getEmployeeCount(employee)).thenReturn(0); 18 19 EmployeeService employeeService = new EmployeeService(); 20 employeeService.saveOrUpdate(employee); 21 22 Mockito.verify(employeeDao).creatEmployee(employee); 23 Mockito.verify(employeeDao, Mockito.never()).updateEmployee(employee); 24 } catch (Exception e) { 25 fail("测试失败..."); 26 } 27 } 28 29 /** 30 * 测试分支及Mockito.verify,在类上添加两个注解: 31 * 32 * @RunWith(PowerMockRunner.class) 33 * @PrepareForTest(EmployeeService.class) 34 */ 35 @Test 36 public void saveOrUpdateTest2() { 37 Employee employee = PowerMockito.mock(Employee.class); 38 EmployeeDao employeeDao = PowerMockito.mock(EmployeeDao.class); 39 try { 40 41 PowerMockito.whenNew(EmployeeDao.class).withNoArguments().thenReturn(employeeDao); 42 PowerMockito.when(employeeDao.getEmployeeCount(employee)).thenReturn(1); 43 44 EmployeeService employeeService = new EmployeeService(); 45 employeeService.saveOrUpdate(employee); 46 47 Mockito.verify(employeeDao, Mockito.never()).creatEmployee(employee); 48 Mockito.verify(employeeDao).updateEmployee(employee); 49 } catch (Exception e) { 50 fail("测试失败..."); 51 } 52 } 53 }
四、参数使用
4.1 org.mockito.Matchers使用
1 /** 2 * org.mockito.Matchers使用:Matchers.anyString() 3 * 4 * @RunWith(PowerMockRunner.class) 5 * @PrepareForTest(EmployeeService.class) 6 */ 7 @Test 8 public void getEmployeeByNameTest1() throws Exception { 9 EmployeeDao employeeDao = PowerMockito.mock(EmployeeDao.class); 10 PowerMockito.whenNew(EmployeeDao.class).withNoArguments().thenReturn(employeeDao); 11 PowerMockito.when(employeeDao.getEmployeeByName(Matchers.anyString())).thenReturn("hello"); 12 EmployeeService employeeService = new EmployeeService(); 13 employeeService.getEmployeeByName(Matchers.anyString()); 14 }
4.2 ArgumentMatcher使用
注意还使用了Matchers.argThat(new MyArgumentMatcher())
/** * ArgumentMatcher使用 * * @RunWith(PowerMockRunner.class) * @PrepareForTest(EmployeeService.class) */ @Test public void getEmployeeByNameTest2() throws Exception { EmployeeDao employeeDao = PowerMockito.mock(EmployeeDao.class); PowerMockito.whenNew(EmployeeDao.class).withNoArguments().thenReturn(employeeDao); PowerMockito.when(employeeDao.getEmployeeByName(Matchers.argThat(new MyArgumentMatcher()))).thenReturn("hello"); EmployeeService service = new EmployeeService(); Assert.assertEquals("hello", service.getEmployeeByName("selectOne")); Assert.assertEquals("hello", service.getEmployeeByName("selectTwo")); Assert.assertEquals("hello", service.getEmployeeByName("selectThree")); /** * 如果采用其他String就会报错,如下: * Assert.assertEquals("hello",service.getEmployeeByName("Others")); */ } private class MyArgumentMatcher extends ArgumentMatcher<String> { @Override public boolean matches(Object argument) { String value = (String) argument; switch (value) { case "selectOne": case "selectTwo": case "selectThree": return true; default: return false; } } }
原文:https://www.cnblogs.com/gzhcsu/p/13381161.html