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(...)方法验证我们的结果。