你的位置:首页 > Java教程

[Java教程]使用PowerMock进行Mock测试


安装

下载地址:https://github.com/jayway/powermock/wiki/Downloads。下载" Mockito and JUnit including dependencies"版本。当前版本为”powermock-mockito-junit-1.6.3.zip"。

IntelliJ IDEA的设置如下:

右击工程,选择“Open Module Settings”

在”Module Settings”对话框中选择test,标识为Test Sources,关闭”Module Settings”对话框。

Eclipse中只需要上述jar包放在工程下的lib目录即可。

Maven在pom.

快速入门

下面创建EmployeeController类用于给Employee类执行Create, Read, Update, and Delete (CRUD)。实际工作由EmployeeService完成。getProjectedEmployeeCount方法预计公司员工每年增加20%,并返回近似取整。

public class EmployeeController {    private EmployeeService employeeService;    public EmployeeController(EmployeeService employeeService) {    this.employeeService = employeeService;  }    public int getProjectedEmployeeCount() {    final int actualEmployeeCount = employeeService.getEmployeeCount();    return (int) Math.ceil(actualEmployeeCount * 1.2);  }    public void saveEmployee(Employee employee) {    employeeService.save(employee);  }  }

 

public class EmployeeService {    public int getEmployeeCount() {    throw new UnsupportedOperationException();  }    public void save(Employee employee) {    throw new UnsupportedOperationException();  }  }

 

由于getEmployeeCount等方法没有真正实现,我们需要mock:

public class Employee {}

import static org.junit.Assert.*;import org.junit.Test;import org.mockito.Mockito;import org.powermock.api.mockito.PowerMockito;public class EmployeeControllerTest {  @Test  public void shouldReturnProjectedCountOfEmployeesFromTheService() {        EmployeeService mock = PowerMockito.mock(EmployeeService.class);    PowerMockito.when(mock.getEmployeeCount()).thenReturn(8);    EmployeeController employeeController = new EmployeeController(mock);    assertEquals(10, employeeController.getProjectedEmployeeCount());  }    @Test  public void  shouldInvokeSaveEmployeeOnTheServiceWhileSavingTheEmployee() {        EmployeeService mock = PowerMockito.mock(EmployeeService.class);      EmployeeController employeeController = new EmployeeController(mock);    Employee employee = new Employee();    employeeController.saveEmployee(employee);    Mockito.verify(mock).saveEmployee(employee);  }    }

上面的saveEmployee(Employee)没有返回值,我们只需要用verify确认有调用即可。

另外有个非常用的MockSettings功能,用于设置mock名、实现额外接口(参见https://groups.google.com/forum/?fromgroups=#!topic/mockito/YM5EF0x90_4)、开启详细日志、注册listener用于mock时通知消息调用。比如:

    EmployeeService mock = PowerMockito.mock(EmployeeService.class, Mockito.withSettings()        .name("EmployeeServiceMock").verboseLogging());

 

模拟静态方法

修改类Employee:

public class Employee {    public static int count() {    throw new UnsupportedOperationException();    }}

新建EmployeeServiceTest类:

import static org.junit.Assert.*;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;@RunWith(PowerMockRunner.class)@PrepareForTest(Employee.class)public class EmployeeServiceTest {  @Test  public void shouldReturnTheCountOfEmployeesUsingTheDomainClass() {          PowerMockito.mockStatic(Employee.class);      PowerMockito.when(Employee.count()).thenReturn(900);          EmployeeService employeeService = new      EmployeeService();      assertEquals(900, employeeService.getEmployeeCount());      }}

@RunWith(PowerMockRunner.class)语句告诉JUnit用PowerMockRunner来执行测试。
@PrepareForTest(Employee.class)语句告诉PowerMock准备Employee类进行测试。适用于模拟final类或有final, private, static, native
方法的类。
注意这里使用的是mockStatic而不是上面的mock。

下面我们模拟下返回void的静态方法。在EmployeeService添加加薪方法:

public class EmployeeService {      public int getEmployeeCount() {        throw new UnsupportedOperationException();    }      public void save(Employee employee) {        throw new UnsupportedOperationException();    }        public boolean giveIncrementToAllEmployeesOf(int percentage) {        try{            Employee.giveIncrementOf(percentage);            return true;        } catch(Exception e) {            return false;        }    }  }

修改EmployeeServiceTest类

import static org.junit.Assert.*;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;@RunWith(PowerMockRunner.class)@PrepareForTest(Employee.class)public class EmployeeServiceTest {    @Test    public void shouldReturnTrueWhenIncrementOf10PercentageIsGivenSuccessfully() {              PowerMockito.mockStatic(Employee.class);        PowerMockito.doNothing().when(Employee.class);        Employee.giveIncrementOf(10);        EmployeeService employeeService = new EmployeeService();        assertTrue(employeeService.giveIncrementToAllEmployeesOf(10));      }          @Test      public void shouldReturnFalseWhenIncrementOf10PercentageIsNotGivenSuccessfully() {          PowerMockito.mockStatic(Employee.class);          PowerMockito.doThrow(new IllegalStateException()).when(Employee.class);          Employee.giveIncrementOf(10);          EmployeeService employeeService = new EmployeeService();          assertFalse(employeeService.giveIncrementToAllEmployeesOf(10));      }}

PowerMockito.doNothing方法告诉PowerMock下一个方法调用时什么也不做。
PowerMockito.doThrow方法告诉PowerMock下一个方法调用时产生异常。

PowerMock使用自定义类加载器和字节码操作来模拟静态方法。对于实例中没有mock的方法,也有默认返回值,比如返回int类型的方法,默认返回0。
PowerMockito.doNothing和PowerMockito.doThrow的语法可用于实例方法。

先修改Employee类:

public class Employee {      public static int count() {        throw new UnsupportedOperationException();    }        public static void giveIncrementOf(int percentage) {        throw new UnsupportedOperationException();    }        public void save() {        throw new UnsupportedOperationException();    }      }

创建测试类:

import static org.junit.Assert.*;import org.junit.Test;import org.powermock.api.mockito.PowerMockito;public class EmployeeTest {    @Test()  public void shouldNotDoAnythingIfEmployeeWasSaved() {    Employee employee = PowerMockito.mock(Employee.class);    PowerMockito.doNothing().when(employee).save();    try {      employee.save();    } catch(Exception e) {      fail("Should not have thrown an exception");    }  }  @Test(expected = IllegalStateException.class)  public void shouldThrowAnExceptionIfEmployeeWasNotSaved() {    Employee employee =    PowerMockito.mock(Employee.class);    PowerMockito.doThrow(new IllegalStateException()).when(employee).save();    employee.save();  }}

注意这里doThrow和doNothing方法不会对下一行产生影响。