您的位置:首页 > 其它

PowerMock详解

2016-09-04 20:38 387 查看

- 概述

PowerMock有两个重要的注解:

@RunWith(PowerMockRunner.class)

@prepareForTest({MyObect.class})

@PrepareForTest注解和@RunWith注解是结合使用的,不要单独使用它们中的任何一个,否则不起作用。当使用

PowerMock去mock静态,final或者私有方法时,需要加上这两个注解。

注意,在你输入@RunWith注解时,Eclipse会自动导入org.powermock.modules.junit4.legacy.PowerMockRunner包,记得把它换成org.powermock.modules.junit4.PowerMockRunner,否则会抛java.lang.NoClassDefFoundError.

- 普通Mock(1)

测试目标代码:
public boolean callArgumentInstance(File file) {
return file.exists();
}
测试用例代码: 
@Test
public void testCallArgumentInstance() {
File file = PowerMockito.mock(File.class);
ClassUnderTest underTest = new ClassUnderTest();
PowerMockito.when(file.exists()).thenReturn(true);
Assert.assertTrue(underTest.callArgumentInstance(file));
}
说明:普通Mock不需要加@RunWith和@PrepareForTest注解。

- 普通Mock(2)

测试目标代码:

public String getFilePath() {
return path;
}
public String getPayloadName() {
String pathWithName = getFilePath();
try {
int index = pathWithName.lastIndexOf(Constant.SLASH);
<span style="white-space:pre">	</span>return pathWithName.substring(index + 1);
}
catch (Exception e) {
<span style="white-space:pre">	</span>return pathWithName;
}
}


测试用例代码: 

@Test
public void testGetPayloadName() throws Exception {
FileItem item = PowerMockito.mock(FileItem.class);
String filePath = "../../../test/updates/Citrix.ibr";
PowerMockito.when(item.getFilePath()).thenReturn(filePath);
PowerMockito.when(item, "getPayloadName").thenCallRealMethod();
assertEquals("Citrix.ibr", item.getPayloadName());
}
说明:当使用mock出来的对象去调用某个方法时,要对该方法使用thenCallRealMethod().

- whenNew

测试目标代码:
public class ClassUnderTest {
public boolean callInternalInstance(String path) {
File file = new File(path);
return file.exists();
}
}
测试用例代码:    
@RunWith(PowerMockRunner.class)
@PrepareForTest(ClassUnderTest.class)
public class TestClassUnderTest {
@Test
public void testCallInternalInstance() throws Exception {
File file = PowerMockito.mock(File.class);
ClassUnderTest underTest = new ClassUnderTest();
PowerMockito.whenNew(File.class).withArguments("bing").thenReturn(file);
PowerMockito.when(file.exists()).thenReturn(true);
Assert.assertTrue(underTest.callInternalInstance("bing"));
}
}
说明:当使用PowerMockito.whenNew方法时,必须加@PrepareForTest和@RunWith注解。注解@PrepareForTest里写的类是需要mock的new对象代码所在的类。

- Mock final方法

测试目标代码:

public class ClassUnderTest{
public boolean callFinalMethod(Dependency d){
<span style="white-space:pre">	</span>return d.isAlive();
}
}
class Dependency{
public final boolean isAlive(){
<span style="white-space:pre">	</span>// do something
<span style="white-space:pre">	</span>return true;
}
}


测试用例代码:

@RunWith(PowerMockRunner.class)
public class TestClassUnderTest {
@Test
@PrepareForTest(Dependency.class)
public void testCallFinalMethod() {
Dependency depencency =  PowerMockito.mock(Dependency.class);
ClassUnderTest underTest = new ClassUnderTest();
PowerMockito.when(depencency.isAlive()).thenReturn(true);
Assert.assertTrue(underTest.callFinalMethod(depencency));
}
}
 说明: 当需要mock final方法的时候,必须加@PrepareForTest和@RunWith注解,@PrepareForTest里写的类是final方法所在的类。
 

- Mock私有方法

测试目标代码:
public class ClassUnderTest{
public boolean callPrivateMethod(){
<span style="white-space:pre">	</span>return isAlive();
}
private boolean isAlive(){
<span style="white-space:pre">	</span>// do something
<span style="white-space:pre">	</span>return true;
}
}
测试用例代码:
@RunWith(PowerMockRunner.class)
@PrepareForTest(ClassUnderTest.class)
public class TestClassUnderTest {
@Test
public void testCallFinalMethod() {
ClassUnderTest underTest = new ClassUnderTest();
<span style="white-space:pre">	</span>PowerMockito.when(underTest.callPrivateMethod().thenCallRealMethod();
PowerMockito.when(underTest, "isAlive").thenReturn(true);
Assert.assertTrue(underTest.callPrivateMethod());
}
}
说明: 和mock final方法一样,必须加@PrepareForTest和@RunWith注解,@PrepareForTest里写的类是private方法所在的类。

- Mock静态方法

测试目标代码:
public class ClassUnderTest{
public boolean callStaticMethod(Dependency d){
<span style="white-space:pre">	</span>return Dependency.isExist();
}
}
class Dependency{
public static boolean isExist(){
<span style="white-space:pre">	</span>// do something
<span style="white-space:pre">	</span>return true;
}
}
测试用例代码:
@RunWith(PowerMockRunner.class)
public class TestClassUnderTest {
@Test
@PrepareForTest(Dependency.class)
public void testCallFinalMethod() {
PowerMockito.mockStatic(Dependency.class);
ClassUnderTest underTest = new ClassUnderTest();
PowerMockito.when(Dependency.isExist()).thenReturn(true);
Assert.assertTrue(underTest.callStaticMethod(depencency));
}
}
说明: mock静态方法时需要加@PrepareForTest和@RunWith注解,@PrepareForTest注解中是静态方法所在的类。

- suppress

测试目标代码:
public class RefreshMgmt{
private static final String MSG_DOWNLOAD_FAILED = Messages.getString("RefreshThread.0");
public boolean downloadFiles(String path) {
return download(path);
}
private boolean download(String localPath){
<span style="white-space:pre">	</span>// do something
<span style="white-space:pre">	</span>return false;
}
}
测试用例代码:
@RunWith(PowerMockRunner.class)
@PrepareForTest({ RefreshMgmt.class, Messages.class })
public class TestRefreshMgmt {
@Test
public void testDownloadFiles() throws Exception {
PowerMockito.suppress(PowerMockito.method(Messages.class, "getString",  String.class));
<span style="white-space:pre">	</span>//PowerMockito.suppress(PowerMockito.field(RefreshMgmt.class,  "MSG_DOWNLOAD_FAILED");
RefreshMgmt mgmt = PowerMockito.mock(RefreshMgmt.class);
PowerMockito.when(mgmt, "download", Matchers.anyString()).thenReturn(true);
PowerMockito.when(mgmt.downloadFiles(Matchers.anyString())).thenCallRealMethod();
assertTrue(mgmt.downloadFiles("C:/temp"));
}
}
说明: PowerMockito.suppress方法原来禁用某个域或方法,在本例中初始化Messages类会抛出空指针异常,因

此用suppress方法来跳过这个field的初始化。

PowerMockito.suppress(PowerMockito.constructor(BaseEntity.class))表示禁用BaseEntity的构造函数
PowerMockito.suppress(PowerMockito.constructor(BaseEntity.class, String.class,  Integer.class))表示禁用参数为String和Integer类型的BaseEntity构造方法。
PowerMockito.suppress(PowerMockito.method(BaseEntity.class, "performAudit", String.class))表示禁用BaseEntity的performAudit方法。
@SuppressStaticInitializationFor("BaseEntity")表示禁用BaseEntity的静态初始化。注意引号部分通常需要全名,比如"com.gitshah.powermock.BaseEntity"。
PowerMockito.suppress(PowerMockito.field(BaseEntity.class,"identifier")):禁用identifier域。

- WhiteBox

测试目标代码:
public class CataElement{
private boolean isAvailable = false;
private List<FileItem> items = new ArrayList<>();
private Date parseDate(String date) {
if(!isAvailable)
<span style="white-space:pre">	</span>return null;
SimpleDateFormat sdf = new SimpleDateFormat("MM/dd/yyyy");
try {
if (date == null || date.isEmpty())
return null;
return sdf.parse(date);
}
catch (ParseException e) {
Log.log(Log.WARN, e, getClass());
return null;
}
}
}
测试用例代码:
public class CataElementTest{
@Test
public void test(){
CataElement e = new CataElement();
Whitebox.setInternalState(e, "isAvailable", true);
// other things
<span style="white-space:pre">	</span>List<FileItem> items = Whitebox.getInternalState(e, "items");
<span style="white-space:pre">	</span>assertTrue(items.size == 0);
}
}

Whitebox.setInternalState(object, "fieldName", value)可以设置某个对象的某个field。
Whitebox.getInternalState(object, "fieldName")获取某个对象的某个field的值。
Whitebox.invokeMethod(object, methodName, para)可以调用私有方法,测试私有方法的返回值。

- Answer

测试用例代码:
@Test
public void test() {
final EmployeeService mock = PowerMockito.mock(EmployeeService.class);
final Employee employee = new Employee();
PowerMockito.when(mock.findEmployeeByEmail(Matchers.anyString())).then(new Answer<Employee>() {
<span style="white-space:pre">	</span>public Employee answer(InvocationOnMock invocation) throws Throwable {
<span style="white-space:pre">	</span>    final String email = (String) invocation.getArguments()[0];
<span style="white-space:pre">	</span>    if(email == null) return null;
<span style="white-space:pre">	</span>    if(email.startsWith("deep")) return employee;
<span style="white-space:pre">	</span>    if(email.endsWith("packtpub.com")) return employee;
<span style="white-space:pre">	</span>    return null;
<span style="white-space:pre">	</span>}
});
final EmployeeController employeeController = new EmployeeController(mock);
assertSame(employee, employeeController.findEmployeeByEmail("deep@gitshah.com"));
assertSame(employee, employeeController.findEmployeeByEmail("deep@packtpub.com"));
assertNull(employeeController.findEmployeeByEmail("hello@world.com"));
}
说明:改测试方法根据不同的参数返回不同的结果,Answer的泛型类型必须和answer方法的返回值类型一致。

Answer接口指定执行的action和返回值。Answer的参数是InvocationOnMock的实例,支持:

callRealMethod():调用真正的方法

getArguments():获取所有参数

getMethod():返回mock实例调用的方法

getMock():获取mock实例

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息