PowerMock教程
1.概述
Mockito是一个强大的、开源的Java模拟框架。它为单元测试提供的特性不可避免地是独特的和重要的,尽管如此,在编写单元测试用例时,它为开发人员减轻了许多工作。
虽然Mockito可以帮助几乎所有的事情,但有些事情它不能做。比如存根或测试私有、final或静态方法。为这些方法编写测试用例需要更多的能力,这通常会导致开发人员为这些方法编写繁琐的代码。
在这里,PowerMockito来救援。PowerMockito能够测试私有、最终或静态方法,因为它使用Java反射API。在我们研究它的用途时,让我们看看实际的演示。
2.创建一个简单的Java Maven项目。
3.使用Maven添加依赖项
正如我们之前谈过的那样,Mockito或者PowerMockito开始的最佳方式是找到它的Maven依赖关系并将其添加到我们的项目中。
以下是我们需要添加的依赖项:
<dependency>
<groupId>org.powermock</groupId>
<artifactId>powermock-module-junit4</artifactId>
<version>1.6.4</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.powermock</groupId>
<artifactId>powermock-api-mockito</artifactId>
<version>1.6.4</version>
<scope>test</scope>
</dependency>
现在我们正在添加依赖项,让我们在测试中使用注释。
pom.xml如下所示:
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>org.igi.theitroad</groupId> <artifactId>PowerMockitoExample</artifactId> <version>0.0.1-SNAPSHOT</version> <dependencies> <dependency> <groupId>org.powermock</groupId> <artifactId>powermock-module-junit4</artifactId> <version>1.6.4</version> <scope>test</scope> </dependency> <dependency> <groupId>org.powermock</groupId> <artifactId>powermock-api-mockito</artifactId> <version>1.6.4</version> <scope>test</scope> </dependency> </dependencies> </project>
4.启用PowerMock注释
就像我们对Mockito所需的一样,我们还需要使用PowerMockito使用注释。
像Mockito一样,我们利用类似的注释,如图所示:
import org.junit.runner.RunWith;
import org.powermock.core.classloader.annotations.PrepareForTest;
import org.powermock.modules.junit4.PowerMockRunner;
@RunWith(PowerMockRunner.class)
@PrepareForTest(fullyQualifiedNames = "org.igi.theitroad.*")
public class PowerTest {
...
}
让我们看看我们上面使用的每个注释:
- @runwith注释类似于我们在模仿中所做的事情。我们将在测试中使用PowerMockRunner使用PowermockRunner,而不是使用Mockito。
- @preparefortest是一个完全预定的name包,带有通配符。这通知PowerMockito程序准备Java Reflection API进行测试。
5.Mocking最终方法
让我们开始使用PowerMockito API来通过模拟最终方法。
要模拟最终方法,并不多令人惊讶,我们应该首先定义最终方法。
这是我们将测试的模型的示例:
package org.igi.theitroad.model;
public class ClassWithFinalMethods {
public final String printMessage(String message) {
return message;
}
}
简单,该方法只返回传递给它的字符串。
现在,现在是时候写下测试了:
package org.igi.theitroad.powermock;
import org.igi.theitroad.model.ClassWithFinalMethods;
import org.junit.Assert;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mockito;
import org.powermock.api.mockito.PowerMockito;
import org.powermock.core.classloader.annotations.PrepareForTest;
import org.powermock.modules.junit4.PowerMockRunner;
@RunWith(PowerMockRunner.class)
@PrepareForTest(fullyQualifiedNames = "org.igi.theitroad.*")
public class PowerMockFinalMethodTest
{
@Test
public void testClassWithFinalMethods_printMessage_finalMethod() throws Exception {
String message = "Hello PowerMockito"; //1
ClassWithFinalMethods mockObject = PowerMockito.mock(ClassWithFinalMethods.class); //2
PowerMockito.whenNew(ClassWithFinalMethods.class).withNoArguments().thenReturn(mockObject); //3
ClassWithFinalMethods object = new ClassWithFinalMethods(); //4
PowerMockito.verifyNew(ClassWithFinalMethods.class).withNoArguments(); //5
PowerMockito.when(object.printMessage(message)).thenReturn(message); //6
String helloPowerMockito = object.printMessage(message); //7
Mockito.verify(object).printMessage(message); //8
Assert.assertEquals(message, helloPowerMockito); //9
}
}
我们使用方法使用类名,以便在导入类时不会发生混淆。
让我们解释在上面的测试中发生的整个很多:
- 我们定义了一个通用字符串消息,我们将使用作为参数和期望。
- 我们嘲笑正在测试的系统的实例,classwithfinalmethods。
- 当new()方法确保每当通过调用no参数构造函数使用新关键字进行此类的实例时,返回此模拟实例而不是实际对象。
- 我们调用无参数构造函数来制作被测系统的实例。
- 我们验证了在最后一步中实际涉及的任何参数构造函数。
- 当调用最终方法时,我们使用步骤1中定义的字符串设置了一个预期的字符串。
- 调用最终方法PrintMessage(...)。
- 我们验证了最终的方法是否实际调用。
- 最后,我们将我们的期望视为返回给我们的实际字符串。
现在实际上很多。
我们使用了一个简单的例子,使一切都有意义。
正如我们用静态方法明确地使用类名,就像使用此测试即可运行。
我们现在通过最终方法。
现在是时候了解如何用Powermockito测试静态方法。
我们使名为ClassWithStaticMethod的新类并添加新方法,它是静态的:
package org.igi.theitroad.model;
public class ClassWithStaticMethod {
public static String printMessage(String message) {
return message;
}
}
类似的方法如前所述,该方法刚刚返回传递给它的字符串。
现在,现在是时候写下测试了:
package org.igi.theitroad.powermock;
import org.igi.theitroad.model.ClassWithStaticMethod;
import 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(fullyQualifiedNames = "org.igi.theitroad.*")
public class PowerMockStaticMethodTest
{
@Test
public void testClassWithStaticMethod_printMessage_staticMethod() {
String message = "Hello PowerMockito"; //1
String expectation = "Expectation"; //2
PowerMockito.mockStatic(ClassWithStaticMethod.class); //3
PowerMockito.when(ClassWithStaticMethod.printMessage(message)).thenReturn(expectation); //4
String actual = ClassWithStaticMethod.printMessage(message); //5
Assert.assertEquals(expectation, actual); //6
}
}
该测试小于前面。
让我们谈谈我们在此进行的每一步:
- 我们定义了一个通用字符串消息,我们将使用作为参数。
- 另一个通用字符串消息,用作期望。
- 准备ClassWithStaticMethod进行静态方法测试。
- 在调用静态方法时准备期望。
- 调用静态方法。
- 验证预期和实际结果。
实际上测试静态方法非常简单。
关键部分是调用powermockito.mockstatic(...),以便为类启用PowerMockito API。
在最后一个位,在本节中,我们将测试私有方法。
这是Java中反射API的另一个令人敬畏的使用。
首先,我们定义了我们的测试系统:
package org.igi.theitroad.model;
public class ClassWithPrivateMethods {
private String printMessage(String message) {
return message;
}
public String privateCall(String message) {
return printMessage(message);
}
}
现在,定义内部调用私信的公共消息是必要的。
让我们看看我们的测试,看看它是如何利用反射API的考验:
package org.igi.theitroad.powermock;
import org.igi.theitroad.model.ClassWithPrivateMethods;
import 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(fullyQualifiedNames = "org.igi.theitroad.*")
public class PowerMockPrivateMethodTest
{
@Test
public void testClassWithPrivateMethods_printMessage_privateMethod() throws Exception {
String message = "Hello PowerMockito";
String expectation = "Expectation";
ClassWithPrivateMethods mock = PowerMockito.spy(new ClassWithPrivateMethods());
PowerMockito.doReturn(expectation).when(mock, "printMessage", message);
String actual = mock.privateCall(message);
Assert.assertEquals(expectation, actual);
}
}
其中,需要指出的是:
- 我们首先使用powermockito.spy(...)方法创建模拟。
- 接下来,我们通过将方法名称作为字符串参数提供给(...)方法来使用反射API。
- 最后,我们调用公共方法,又调用私有方法,并使用Assertequals(...)方法验证我们的结果。

