Powermock扩展了EasyMock的功能。它使用定制的类加载器,通过字节码操作提供了对静态方法、构造方法、final类与final方法、以及私有方法的mock能力。
当前PowerMock支持EasyMock和Mockito。
一、bypass封装:
Whitebox类提供了一些可以帮你bypass封装的方法。
1)使用Whitebox.setInternalState(..)来设置实例或者是类的非public成员。
2)使用Whitebox.getInternalState()来获取实例或者是类的非public成员
3)使用Whitebox.invokeMethod(..)调用实例或者类的非公共方法
4)使用Whitebox.invokeConstructor(..)来创建带private构造方法的类的实例
eg:
1、访问内部状态
对于可变对象,其内部状态可能在某个方法调用后改变。当对这类对象进行单元测试时,如果有某种简单的方法可以持有这个状态并检测这个状态是否一致更新就最好了。PowerMock提供了多个有用的反射工具来支持这个功能,这些反射工具都在 org.powermock.reflect.Whitebox这个类中。
举个列子:我们有这样一个类
public class ServiceHolder {
private final Set<Object> services = new HashSet<Object>();
public void addService(Object service) {
services.add(service);
}
public void removeService(Object service) {
services.remove(service);
}
}
比如,我们要测试addService()方法,我们要确保ServiceHolder在addService方法被调用后其状态正确更新,也就是说,往services集合中添加了一个对象。一个办法是提供一个包private或者protected的方法,如getServices()来返回services,但是这样做的话,我们得向ServiceHolder中添加一个方法,而这么做仅仅只是为了让这个类具有可测试性。另一个可选的办法是使用Whitebox.getInternalState(..)方法来完成这个目的,而无需”制造“新的代码。在这个例子中,addService方法的可能如下:
package com.larry.junit;
import java.util.Set;
import junit.framework.Assert;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.powermock.core.classloader.annotations.PrepareForTest;
import org.powermock.modules.junit4.PowerMockRunner;
import org.powermock.reflect.Whitebox;
@RunWith(PowerMockRunner.class)
@PrepareForTest({})
public class ServiceHolderTest {
@Test
public void testAddService() {
ServiceHolder tested = new ServiceHolder();
final Object service = new Object();
tested.addService(service);
//使用PowerMock访问私有域
Set<Object> services = Whitebox.getInternalState(tested, "services");
Assert.assertEquals("services size expected is: ", 1, services.size());
Assert.assertSame("services should contain the expected service", service,
services.iterator().next());
}
}
使用PowerMock1.0以及以上版本还可以通过指定域的类型来获取内部状态。在上面这个例子中,我们可以这样写:
package com.larry.junit;
import java.util.Set;
import junit.framework.Assert;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.powermock.core.classloader.annotations.PrepareForTest;
import org.powermock.modules.junit4.PowerMockRunner;
import org.powermock.reflect.Whitebox;
@RunWith(PowerMockRunner.class)
@PrepareForTest({})
public class ServiceHolderTest {
@Test
public void testAddService() {
ServiceHolder tested = new ServiceHolder();
final Object service = new Object();
tested.addService(service);
//使用PowerMock访问私有域
// Set<Object> services = Whitebox.getInternalState(tested, "services");
Set<Object> services = Whitebox.getInternalState(tested, Set.class);
Assert.assertEquals("services size expected is: ", 1, services.size());
Assert.assertSame("services should contain the expected service", service, services.iterator().next());
}
}
这种做法更安全,基于这个原因也更推荐这样写。但是,如果某个类型有多个域,那么还是的使用第一种直接使用域的名称的方法。
2、设置对象内部状态
设置对象内部状态也很容易。假设有下面一个类:
public class ReportGenerator {
@Injectable
private ReportTemplateService reportTemplateService;
public Report generateReport(String reportId) {
String templateId = reportTemplateService.getTemplateId(reportId);
/*
* Imagine some other code here that generates the report based on the
* template id.
*/
return new Report("name");}
}
}
假设我们使用了一个依赖注入框架,它可以在运行时自动给我们提供ReportTemplateService类的一个实例。我们有多种选择测试这个类。例如,我们可以重构这个类使用构造方法或者setter注入,使用Java反射机制或者我们自己创建一个reportTemplateService的setter方法。另一个办法就是让PowerMock通过Whitebox.setInternalState(..)方法。
Whitebox.setInternalState(tested, "reportTemplateService", reportTemplateServiceMock);
3、调用私有方法
要调用私有方法,可以使用Whitebox.invokeMethod(..)方法。例如,myInstance实例中,我们有一个要测试的private方法sum():
private int sum(int a, int b) {
return a+b;
}
你只需要这样做:
int sum = Whitebox.<Integer> invokeMethod(myInstance, "sum", 1, 2);
sum的值将为3.
代码:
package com.larry.junit;
import junit.framework.Assert;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.powermock.modules.junit4.PowerMockRunner;
import org.powermock.reflect.Whitebox;
@RunWith(PowerMockRunner.class)
public class SumTest {
@Test
public void testSum() throws Exception {
Sum myInstance = new Sum();
int result = Whitebox.invokeMethod(myInstance, "sum", 1, 2);
Assert.assertEquals(3, result);
}
}
大多情况下,这种做法运行良好。然而有些时候,使用这种方法PowerMock分不清楚它要调用的到底是哪个方法,可能测试结果与我们的预期不一致,例如我们有两个重载的方法:
package com.larry.junit;
public class Sum {
private int sum(int a, int b) {
return a + b;
}
private int sum(Integer a, Integer b) {
return a * b;
}
}
那么我们需要通过明确指定参数类型int来告知PowerMock调用方法。
package com.larry.junit;
import junit.framework.Assert;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.powermock.modules.junit4.PowerMockRunner;
import org.powermock.reflect.Whitebox;
@RunWith(PowerMockRunner.class)
public class SumTest {
@Test
public void testSum() throws Exception {
Sum myInstance = new Sum();
int result = Whitebox.<Integer>invokeMethod(myInstance, "sum", new Class<?>[] {int.class, int.class}, 1, 2);
Assert.assertEquals(3, result);
}
}
相关推荐
PowerMock 是一个强大的Java单元测试框架,它扩展了其它单元测试工具,如Mockito,使得开发者可以模拟静态方法、构造函数、final类和方法、删除静态初始化器等。这款库在进行复杂对象模拟时非常有用,尤其是在处理...
PowerMock 是一个强大的 Java 测试框架的扩展工具,它允许开发者在单元测试中模拟静态方法、构造函数、最终类和删除静态初始化器等通常难以测试的场景。在 Java 单元测试领域,EasyMock 和 JUnit 是两个常用库,...
**PowerMock学习指南** 在Java开发中,单元测试是一项至关重要的任务,它能确保代码的质量和稳定性。然而,有些复杂的代码结构,如静态方法、final类或方法、构造器私有化等,使得传统的单元测试框架如JUnit和...
【PowerMock实战教学】是由汪文君主讲的一系列教程,专注于讲解如何使用PowerMock这一强大的Java单元测试框架。PowerMock是在easymock和mockito的基础上构建的,旨在提供更多的功能,解决传统mock框架无法处理的一些...
PowerMock是一个强大的Java单元测试框架,它扩展了如Mockito这样的工具,允许开发者模拟静态方法、构造函数、final类和方法、私有方法以及删除静态初始化器。在Java开发中,有时我们需要对不可Mock的对象进行单元...
在“二、PowerMock入门”中,读者将学习到PowerMock的基本使用场景、一个简单的“Hello World”示例以及重点API的解释。这些内容都是为了帮助读者快速上手PowerMock。 在后续章节中,将会进一步深入讲解PowerMock的...
赠送jar包:powermock-core-2.0.9.jar; 赠送原API文档:powermock-core-2.0.9-javadoc.jar; 赠送源代码:powermock-core-2.0.9-sources.jar; 赠送Maven依赖信息文件:powermock-core-2.0.9.pom; 包含翻译后的API...
《PowerMock实战手册》是一本专注于使用PowerMock进行单元测试的指南,结合了Junit测试框架和Mockito库,为开发者提供了全面的测试解决方案。在实际的软件开发中,单元测试是确保代码质量的重要环节,它能帮助我们找...
PowerMock Maven Repository是一个重要的开发工具资源库,它主要服务于Java开发者,特别是那些使用PowerMock框架进行单元测试的人员。PowerMock是一个强大的库,允许开发者模拟静态方法、构造函数、删除final修饰、...
PowerMock-Mockito-JUnit-1.6.2.zip 是一个包含PowerMock、Mockito和JUnit集成库的压缩包,适用于Java开发环境。这个版本的PowerMock要求使用1.6或更高版本的Java Development Kit (JDK)。下面将详细解释这三个主要...
PowerMock 是一个强大的Java单元测试框架的扩展,它允许开发者模拟静态方法、构造函数、final 类、enum 和...如果你在IBM DeveloperWorks找到的资源能够提供详细的教程和示例,那么对于学习和应用PowerMock将大有裨益。
PowerMock是一个扩展了其他模拟框架(如EasyMock、Mockito等)的库,它可以模拟静态方法、构造函数、final类和方法、私有方法以及删除静态初始化器等,这些都是传统模拟框架难以处理的情况。在进行单元测试时,有些...
PowerMock就是这样一款强大的工具,它扩展了EasyMock的功能,允许开发者在单元测试中模拟静态方法、构造器、final类和方法、删除静态初始化器等。本文将详细介绍如何使用PowerMock来Mock静态函数,并探讨其背后的...
PowerMock是一个强大的Java单元测试框架,它扩展了其他如EasyMock等工具的功能,允许开发者对静态方法、构造函数、final类和方法、私有方法以及删除静态初始化器进行模拟和测试。在“powerMock的测试样例集合”中,...
赠送jar包:powermock-module-junit4-2.0.9.jar; 赠送原API文档:powermock-module-junit4-2.0.9-javadoc.jar; 赠送源代码:powermock-module-junit4-2.0.9-sources.jar; 赠送Maven依赖信息文件:powermock-...
powermock-classloading-xstream-1.4.7powermock-classloading-xstream-1.4.7powermock-classloading-xstream-1.4.7powermock-classloading-xstream-1.4.7powermock-classloading-xstream-1.4.7powermock-class...
PowerMock是EasyMock的一个扩展,它允许模拟静态方法、构造函数、final类和方法,以及删除静态初始化器。这对于那些不能直接用EasyMock模拟的场景非常有用,例如模拟Java的`java.lang`包中的类。 **运行PowerMock...
PowerMock 也是一个单元测试模拟框架,它是在其它单元测试模拟框架的基础上做出的扩展。通过提供定制的类加载器以及一些字节码篡改技巧的应用,PowerMock 现了对静态方法、构造方法、私有方法以及 Final 方法的模拟...