Java中的PowerMock使用实践
作者:Terisadeng
一、常用注解
@PrepareForTest和@RunWith是成对出现的,一般@RunWith(PowerMockRunner.class),@PrepareForTest的值是引用的静态方法或私有方法的类。
@InjectMocks注解标注的类会被注入所有被@Mock注解标注的类。
@Before注解用于方法,表示在执行@Test注解标注的方法之前执行。
在initMocks()方法中可以执行MockitoAnnotations.initMocks(this);来将@Mock注解修饰的类注入到@InjectMocks修饰的类。
二、实例操作
首先定义三个类,分别是实体类Employee.java,数据操作类EmployeeDao.java,业务逻辑类EmployeeService.java,下面是3个类的具体定义:
public class Employee { private String name; private Double salary; /** * @return the name */ public String getName() { return name; } /** * @param name the name to set */ public void setName(String name) { this.name = name; } /** * @return the salary */ public Double getSalary() { return salary; } /** * @param salary the salary to set */ public void setSalary(Double salary) { this.salary = salary; } }
EmployeeDao.java:
public interface EmployeeDao { public Employee getEmployee(String name); public boolean updateEmployee(Employee employee); public static void deleteEmployee(String name) { throw new NullPointerException(); } public Exception saveEmployee(Employee employee); }
EmployeeService.java:
public class EmployeeServiceImpl { private EmployeeDao employeeDao; public EmployeeServiceImpl() { } public EmployeeServiceImpl(EmployeeDao employeeDao) { this.employeeDao = employeeDao; } public Employee getEmployee(String name) { return employeeDao.getEmployee(name); } public boolean updateEmployee(Employee employee) { return employeeDao.updateEmployee(employee); } public boolean deleteEmployee(String name) { try { EmployeeDao.deleteEmployee(name); return true; } catch (Exception e) { return false; } } public boolean saveEmployee(Employee employee) { try { employeeDao.saveEmployee(employee); return true; } catch (Exception e) { e.printStackTrace(); return false; } } }
PowerMockito知识点
下面是测试类中涉及到的PowerMockito知识点:
1)其中涉及到静态方法,因此需要使用@RunWith(PowerMockRunner.class)
@PrepareForTest({ EmployeeDao.class })注解,PrepareForTest的值是静态方法所在的类或接口,否则会报下面的错误:
org.powermock.api.mockito.ClassNotPreparedException: The class mock.EmployeeDao not prepared for test. To prepare this class, add class to the '@PrepareForTest' annotation. In case if you don't use this annotation, add the annotation on class or method level. at org.powermock.api.mockito.expectation.reporter.MockitoPowerMockReporter.classNotPrepared(MockitoPowerMockReporter.java:32)
2)使用@Before注解在调用@Test注解的方法之前进行初始化,比如使用mock(类的Class对象)来创建需要模拟的对象,这样我们就可以假设被模拟的对象已经实现,尽管他其实是一个没有实现类的接口。
3)在模拟对象创建之后,我们就可以使用when(调用模拟对象的方法).thenReturn(定义方法调用的返回值),这样我们就相当于假设调用被模拟对象的方法后返回的一直是thenReturn中定义的值。这样我们就不用关心被模拟对象的实现按,只关心下面我们测试的业务逻辑是否存在问题。
@RunWith(PowerMockRunner.class) @PrepareForTest({ EmployeeDao.class }) public class EmployeeServiceImplTest { @Mock public EmployeeDao employeeDao; @Mock EmployeeServiceImpl employeeServiceImpl; // @Before注解的方法会在调用测试方法前执行初始化动作 @Before public void initMocks() { // 创建模拟对象EmployeeDao的实例 employeeDao = mock(EmployeeDao.class); // 将模拟对象赋给业务类实例 employeeServiceImpl = new EmployeeServiceImpl(employeeDao); } @Test public void getEmployeeTest() { String name = "scott"; Employee employee = new Employee(); employee.setName("scott"); employee.setSalary(8888.0); // 定义当执行employeeDao.getEmployee(name)方法时始终返回employee对象,相当于实现了employeeDao的这个方法 when(employeeDao.getEmployee(name)).thenReturn(employee); /* * 下面测试我们想要单元测试的employeeServiceImpl.getEmployee(name)方法 我们已经屏蔽了该方法对employeeDao.getEmployee(name)的调用,相当于解除了依赖 * 这样我们只需要关心employeeServiceImpl.getEmployee(name)方法的逻辑是否存在问题 */ Employee employee2 = employeeServiceImpl.getEmployee(name); System.out.println(employee2.getSalary()); } @Test public void updateEmployeeTest() { Employee employee = new Employee(); employee.setName("tiger"); employee.setSalary(99999.0); when(employeeDao.updateEmployee(anyObject())).thenReturn(true); Employee employee2 = new Employee(); employee.setName("scott"); employee.setSalary(99999.0); Boolean boolean1 = employeeServiceImpl.updateEmployee(employee2); System.out.println(boolean1); } @Test public void deleteEmployeeTest() { String name = "haha"; // 因为这里调用的是静态方法,因此使用PowerMockito.mockStatic(EmployeeDao.class);来模拟静态类 PowerMockito.mockStatic(EmployeeDao.class); // 使用doNothing()定义执行下面一句语句时什么也不做 PowerMockito.doNothing().when(EmployeeDao.class); // 这一句由于上面的doNothing()即使会抛异常也不会再抛 EmployeeDao.deleteEmployee(name); // 因此employeeServiceImpl.deleteEmployee(name)执行时也没有发现异常返回true EmployeeServiceImpl employeeServiceImpl = new EmployeeServiceImpl(); Assert.assertTrue(employeeServiceImpl.deleteEmployee(name)); } @Test public void throwDeleteExceptionTest() { String name = "haha"; PowerMockito.mockStatic(EmployeeDao.class); // doThrow()定义下面一句语句会抛出异常 PowerMockito.doThrow(new NullPointerException()).when(EmployeeDao.class); EmployeeDao.deleteEmployee(name); // 因此employeeServiceImpl.deleteEmployee(name)执行会返回false EmployeeServiceImpl employeeServiceImpl = new EmployeeServiceImpl(); assertTrue(employeeServiceImpl.deleteEmployee(name)); } @Test public void saveEmployeeTest() { Employee employee = new Employee(); employee.setName("scott"); employee.setSalary(8888.0); // 打桩,定义方法返回的值 when(employeeDao.saveEmployee(employee)).thenReturn(new NullPointerException()); // 这里doNothing()没有生效,原因是这里调用的是实例方法,不是静态方法 PowerMockito.doNothing().when(employeeDao).saveEmployee(employee); employeeServiceImpl.saveEmployee(employee); } @Test public void throwSaveEmployeeTest() { Employee employee = new Employee(); employee.setName("scott"); employee.setSalary(8888.0); when(employeeDao.saveEmployee(employee)).thenReturn(new NullPointerException()); // 这里的doThrow()实际没有生效,因为这里调用的是实例方法,不是静态方法,因此不存在使下一句语句抛异常的作用 PowerMockito.doThrow(new NullPointerException()).when(employeeDao).saveEmployee(employee); employeeServiceImpl.saveEmployee(employee); } }
到此这篇关于Java中的PowerMock使用实践的文章就介绍到这了,更多相关PowerMock使用内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!