使用 PowerMockito 在 Java 单元测试中模拟 final 和 static 方法
本文档提供了两个 Maven 示例项目,用于使用 PowerMockito 在 Java 单元测试中模拟 final 和 static 方法。
引言
本文档提供了两个 Maven 示例项目,用于使用 PowerMockito 在 Java 单元测试中模拟 final 和 static 方法。一个项目用于 JUnit,另一个项目用于 TestNG。
背景
在编写单元测试时,我们可能需要不断地模拟某些类,以便我们不必经历完整的运行机制来测试代码。根据 stack-overflow 讨论,Mockito 是一个备受推崇的模拟框架。但问题是 Mockito 本身没有模拟 final 和 static 方法的能力。如果我们想模拟这些方法,我们需要使用 PowerMock 配合 PowerMockito。 不幸的是,关于如何使用 PowerMockito 的文档并不详细。我不得不经历不少试错才能让它正常工作。
- 大多数使用 PowerMock 的示例都省略了 Java 代码中的“import”部分。我觉得很难弄清楚代码中使用的类属于哪个包;
- Java 中有两种常用的单元测试环境:JUnit 和 TestNG。在不同的单元测试环境中,我们需要以不同的方式使用 PowerMock。
本文档中的示例将为我保留记录,并可能为同样对此主题感兴趣的人节省一些时间。 PowerMock 可以与 EasyMock 或 Mockito 一起使用。本文档仅展示 PowerMockito 的用法。
安装 Maven
附加的示例是 Maven 项目。我们需要 Maven 来运行它们。如果您计算机上没有 Maven,则需要安装它。Maven 是一个 Java 应用程序,您需要安装 JDK,仅安装 JRE 是不够的。我测试使用的 Java 版本是“jdk1.7.0_60”。安装 JDK 后,您可以访问 Maven 网站下载 Maven。我测试使用的 Maven 版本是“3.2.1”。根据文档,我们需要按照以下步骤在 Windows 计算机上完成 Maven 安装。
- 将下载的 zip 文件解压到您想要安装 Maven 的目录;
- 将 M2_HOME 添加到环境变量并将其设置为 Maven 文件所在的目录。在我的例子中,它是 C:\Maven;
- 将 M2 环境变量设置为 %M2_HOME%\bin;
- 将 %M2% 添加到 Path 环境变量;
- 确保环境变量中存在 JAVA_HOME,并将其设置为所需的 JDK 的位置。在我的例子中,它是 C:\Program Files\Java\jdk1.7.0_60;
- 确保 %JAVA_HOME%\bin 存在于 Path 环境变量中。
在 Windows 环境中,很多人可能会对用户环境变量和系统环境变量之间的区别感到困惑。区别如下,
- 系统变量对所有用户可用,而用户变量仅对当前登录到计算机的用户可用;
- 如果同一个环境变量(Path 环境变量除外)在用户变量和系统变量部分都已定义,则用户部分的值会覆盖系统部分的值;
- 如果 Path 环境变量在用户变量和系统变量部分都已定义,则有效的 Path 将是它们连接在一起的结果。
完成所有步骤后,我们可以打开 命令提示符窗口 并输入以下 Maven 命令,
mvn --version
我们应该看到以下结果,这表明 Maven 安装应该已成功。
要模拟的 Final 和 Static 类
为了演示 PowerMockito's 模拟 final 和 static 方法的能力,我创建了以下简单的类。
package org.song.example;
public final class AFinalClass {
public final String echoString(String s) {
return s;
}
}
package org.song.example;
public class AStaticClass {
public static final String echoString(String s) {
return s;
}
}
每个类都实现了一个名为“echoString()”的方法。我将使用这两个方法来演示如何在单元测试程序中使用 PowerMockito 来模拟它们。
Maven 依赖项
本文档附带两个示例 Maven 项目。一个用于 JUnit,另一个用于 TestNG。如果我们想使用 JUnit 运行单元测试,我们需要声明以下依赖项
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.11</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.powermock</groupId>
<artifactId>powermock-api-mockito</artifactId>
<version>1.5.5</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.powermock</groupId>
<artifactId>powermock-module-junit4</artifactId>
<version>1.5.5</version>
<exclusions>
<exclusion>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
</exclusion>
<exclusion>
<groupId>org.powermock</groupId>
<artifactId>powermock-core</artifactId>
</exclusion>
<exclusion>
<groupId>org.powermock</groupId>
<artifactId>powermock-reflect</artifactId>
</exclusion>
</exclusions>
<scope>test</scope>
</dependency>
如果我们想使用 TestNG 运行单元测试,我们需要声明以下依赖项
<dependency>
<groupId>org.testng</groupId>
<artifactId>testng</artifactId>
<version>6.8.8</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.powermock</groupId>
<artifactId>powermock-api-mockito</artifactId>
<version>1.5.5</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.powermock</groupId>
<artifactId>powermock-module-testng</artifactId>
<version>1.5.5</version>
<exclusions>
<exclusion>
<groupId>org.testng</groupId>
<artifactId>testng</artifactId>
</exclusion>
<exclusion>
<groupId>org.powermock</groupId>
<artifactId>powermock-core</artifactId>
</exclusion>
<exclusion>
<groupId>org.powermock</groupId>
<artifactId>powermock-reflect</artifactId>
</exclusion>
</exclusions>
<scope>test</scope>
</dependency>
我们可能需要注意以下关于 Maven 依赖项的问题
- 根据 Maven 文档,TestNG 包将 JUnit 声明为其依赖项,但它被声明为“可选”依赖项。Maven 不会自动将可选依赖项添加到其类路径。对于这个 TestNG 示例,JUnit 是不需要的;
- 在许多情况下,如果 Maven 包定义良好,Maven 可以很好地处理传递性依赖。但最好始终确切了解哪些包已添加到 Maven 类路径中。这就是为什么在“powermock-module-junit4”和“powermock-module-testng”包的依赖项声明中使用包排除,以避免潜在的版本不一致和混淆。
测试类
如果我们想将 PowerMockito 与 JUnit 一起使用,我们需要编写如下所示的单元测试类
package org.song.example;
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({AFinalClass.class, AStaticClass.class})
public class MockTest {
@Test
public void mockFinalClassTest() {
AFinalClass tested = PowerMockito.mock(AFinalClass.class);
final String testInput = "A test input";
final String mockedResult = "Mocked final echo result - " + testInput;
Mockito.when(tested.echoString(testInput)).thenReturn(mockedResult);
// Assert the mocked result is returned from method call
Assert.assertEquals(tested.echoString(testInput), mockedResult);
}
@Test
public void mockStaticClassTest() {
PowerMockito.mockStatic(AStaticClass.class);
final String testInput = "A test input";
final String mockedResult = "Mocked static echo result - " + testInput;
Mockito.when(AStaticClass.echoString(testInput)).thenReturn(mockedResult);
// Assert the mocked result is returned from method call
Assert.assertEquals(AStaticClass.echoString(testInput), mockedResult);
}
}
- 在测试类中添加注解“@RunWith(PowerMockRunner.class)”;
- 在测试类中添加注解“@PrepareForTest({AFinalClass.class, AStaticClass.class})”,其中“AFinalClass”和“AStaticClass”是要测试的类。
如果我们想使用 TestNG 运行单元测试,我们需要编写如下所示的测试类
package org.song.example;
import org.mockito.Mockito;
import org.powermock.api.mockito.PowerMockito;
import org.powermock.core.classloader.annotations.PrepareForTest;
import org.powermock.modules.testng.PowerMockTestCase;
import org.testng.Assert;
import org.testng.annotations.Test;
@PrepareForTest({AFinalClass.class, AStaticClass.class})
public class MockTest extends PowerMockTestCase {
@Test
public void mockFinalClassTest() {
AFinalClass tested = PowerMockito.mock(AFinalClass.class);
final String testInput = "A test input";
final String mockedResult = "Mocked final echo result - " + testInput;
Mockito.when(tested.echoString(testInput)).thenReturn(mockedResult);
// Assert the mocked result is returned from method call
Assert.assertEquals(tested.echoString(testInput), mockedResult);
}
@Test
public void mockStaticClassTest() {
PowerMockito.mockStatic(AStaticClass.class);
final String testInput = "A test input";
final String mockedResult = "Mocked static echo result - " + testInput;
Mockito.when(AStaticClass.echoString(testInput)).thenReturn(mockedResult);
// Assert the mocked result is returned from method call
Assert.assertEquals(AStaticClass.echoString(testInput), mockedResult);
}
}
- 在测试类中添加注解“@PrepareForTest({AFinalClass.class, AStaticClass.class})”,其中“AFinalClass”和“AStaticClass”是要测试的类;
- 测试类需要继承“PowerMockTestCase”类。根据 PowerMockito 的文档,继承“PowerMockTestCase”类只是使测试类工作的选项之一,但也提到继承“PowerMockTestCase”类是“安全”的选项。
运行单元测试
如果您想运行示例项目,您可以下载附加的 zip 文件并将它们解压缩到您想要的文件夹。附加的项目是简单的标准 Maven 项目。解压缩后,您会看到标准的“src”文件夹和“pom.xml”文件。您可以打开命令提示符窗口并导航到包含“pom.xml”文件的文件夹。然后您可以发出以下命令
mvn clean test
下图显示了在 JUnit 测试环境中,final 和 static 方法的模拟已成功。
如果一个项目仅声明了 JUnit 或 TestNG 依赖项但不是两者都有,Maven 将使用声明的单元测试环境来运行测试。附加的简单示例就是这种情况。在更复杂的项目中,如果声明了两种测试环境,您将需要确保使用了所需的单元测试环境。
其他说明
PowerMockito 和 Mockito 协同工作
在测试程序中,一些测试用例需要模拟 final 或 static 方法,而另一些则不需要,这种情况并不少见。重要的是,如果测试用例不需要模拟 final 或 static 方法,我们不要继承“PowerMockTestCase”类。TestNG 会在两种情况下使用不同的对象工厂来创建测试用例实例。如果您在不需要 final 或 static 方法的情况下继承了“PowerMockTestCase”类,单元测试在 Maven 的Surefire 下将无法一致运行。
Final 和 Static 模拟的范围
在同一个测试类中,我们有多个测试方法是非常普遍的。让我们看下面的测试类。
package org.song.example;
import org.mockito.Mockito;
import org.powermock.api.mockito.PowerMockito;
import org.powermock.core.classloader.annotations.PrepareForTest;
import org.powermock.modules.testng.PowerMockTestCase;
import org.testng.Assert;
import org.testng.annotations.Test;
@PrepareForTest({AFinalClass.class, AStaticClass.class})
public class MockTest extends PowerMockTestCase {
private AFinalClass aFinalClass_mock = null;
@Test
public void mockFinalClassTest() {
final String testInput = "A test input";
final String mockedResult = "Mocked final echo result - " + testInput;
aFinalClass_mock = PowerMockito.mock(AFinalClass.class);
Mockito.when(aFinalClass_mock.echoString(testInput)).thenReturn(mockedResult);
// Assert the mocked result is returned from method call
Assert.assertEquals(aFinalClass_mock.echoString(testInput), mockedResult);
}
@Test(dependsOnMethods = {"mockFinalClassTest"})
public void mockFinalClassTest_1() {
final String testInput = "A test input";
final String mockedResult = "Mocked final echo result - " + testInput;
// Assert the mocked result is returned from method call
Assert.assertEquals(aFinalClass_mock.echoString(testInput), mockedResult);
}
@Test
public void mockStaticClassTest() {
PowerMockito.mockStatic(AStaticClass.class);
final String testInput = "A test input";
final String mockedResult = "Mocked static echo result - " + testInput;
Mockito.when(AStaticClass.echoString(testInput)).thenReturn(mockedResult);
// Assert the mocked result is returned from method call
Assert.assertEquals(AStaticClass.echoString(testInput), mockedResult);
}
@Test(dependsOnMethods = {"mockStaticClassTest"})
public void mockStaticClassTest_1() {
final String testInput = "A test input";
final String mockedResult = "Mocked static echo result - " + testInput;
// Assert the mocked result is returned from method call
Assert.assertEquals(AStaticClass.echoString(testInput), mockedResult);
}
}
在上面的类中,“@Test”注解的“dependsOnMethods”属性告诉测试框架先运行“mockFinalClassTest()”再运行“mockFinalClassTest_1()”,以及先运行“mockStaticClassTest()”再运行“mockStaticClassTest_1()”。如果我们运行测试,我们会得到以下结果。
- “mockFinalClassTest_1()”和“ockStaticClassTest_1()”方法都因断言失败;
- 这是因为模拟的作用域仅限于指定它们的测试方法。
常规 Mockito 模拟的作用域
如果一个方法既不是 final 也不是 static,我们可以直接使用 Mockito 来模拟它。模拟的作用域与 final 和 static 方法的模拟不同。让我们看下面的例子。
package org.song.example;
public class RegularClass {
public String Echo(String s) {
return s;
}
}
“RegularClass”是要测试的类,下面是单元测试类。
package org.song.example;
import org.mockito.Mockito;
import org.testng.Assert;
import org.testng.annotations.Test;
public class RegularTest {
private RegularClass instance = null;
@Test
public void test1() {
final String expected = "Expected String";
instance = Mockito.mock(RegularClass.class);
Mockito.doReturn(expected).when(instance).Echo(Mockito.anyString());
Assert.assertEquals(instance.Echo("Song"), expected);
}
@Test(dependsOnMethods = {"test1"})
public void test2() {
final String expected = "Expected String";
Assert.assertEquals(instance.Echo("Song"), expected);
}
}
- “test1”方法初始化了一个“RegularClass”的 Mockito 模拟,并将其分配给实例变量“instance”;
- “test2”只是使用“instance”进行测试,而无需重新初始化模拟。
如果我们运行单元测试,我们可以看到两个测试方法都成功运行。
这个实验向我们表明,常规 Mockito 创建的模拟的作用域超出了创建模拟的测试方法的限制,这与 PowerMockito 创建的 final 和 static 方法的模拟的作用域不同。
使用 PowerMockito 进行 Mock 对象构造 (new)
单元测试的一个挑战是模拟本地创建的对象。有很多关于如何通过应用一些期望的设计模式来使代码更易于单元测试的讨论,以及我们是否应该使用依赖注入。尽管有这些好的设计模式,PowerMockito 确实能够模拟本地创建的对象。让我们看下面的两个类。
package org.song.example;
import java.util.Random;
public class ScoreGrader {
public int getScore() {
Random random = new Random();
int score = 60 + (int) Math.round(40.0 * random.nextDouble());
return score;
}
}
package org.song.example;
public class Student {
public int getMathScore() {
ScoreGrader grader = new ScoreGrader();
return grader.getScore();
}
}
- “ScoreGrader”类实现了一个“getScore”方法,该方法返回一个在 60-100 之间的随机生成的整数;
- “Student”类中的“getMathScore”方法实例化了一个“ScoreGrader”对象并使用它来生成学生的数学分数。
下面是对“Student”类的单元测试,它模拟了“ScoreGrader”类的对象构造 (new)。
package org.song.example;
import org.mockito.Mockito;
import org.powermock.api.mockito.PowerMockito;
import org.powermock.core.classloader.annotations.PrepareForTest;
import org.powermock.modules.testng.PowerMockTestCase;
import org.testng.Assert;
import org.testng.annotations.Test;
@PrepareForTest({Student.class})
public class MockConstructionTest extends PowerMockTestCase {
@Test
public void mockConstruction() {
Student student = new Student();
final int expectedScore = 120;
ScoreGrader grader_mock = Mockito.mock(ScoreGrader.class);
Mockito.doReturn(expectedScore).when(grader_mock).getScore();
try {
PowerMockito.whenNew(ScoreGrader.class)
.withNoArguments().thenReturn(grader_mock);
} catch (Exception e) {
Assert.fail("Unable to mock the construction of "
+ "the ScoreGrader object");
}
// This assertion will succeed because the mock is used to
// generate the score, so a score greater than 100 is generated
Assert.assertEquals(student.getMathScore(), expectedScore);
}
}
- 在“@PrepareForTest”注解中,我们需要指定发生“new”对象构造的类,而不是正在构造的类;
- 对“PowerMockito.whenNew()”方法的调用可以改变对象构造,因此构造过程可以向调用者返回一个模拟对象。
如果我们运行测试,我们会发现它成功了。这表明当发出“ScoreGrader grader = new ScoreGrader();”语句时获得了模拟,因为真正的“ScoreGrader”对象永远无法生成大于 100 的分数。
模拟单例
package org.song.example;
import java.util.Random;
public class SingletonScoreGrader {
private static SingletonScoreGrader instance = null;
private SingletonScoreGrader() {}
public static synchronized SingletonScoreGrader instance() {
if (instance == null) {
instance = new SingletonScoreGrader();
}
return instance;
}
public int getScore() {
Random random = new Random();
int score = 60 + (int) Math.round(40.0 * random.nextDouble());
return score;
}
}
- “SingletonScoreGrader”类是一个典型的单例类;
- “instance”方法返回“SingletonScoreGrader”对象的单个实例。
package org.song.example;
import org.mockito.Mockito;
import org.powermock.api.mockito.PowerMockito;
import org.powermock.core.classloader.annotations.PrepareForTest;
import org.powermock.modules.testng.PowerMockTestCase;
import org.testng.Assert;
import org.testng.annotations.Test;
@PrepareForTest({SingletonScoreGrader.class})
public class MockSingletonTest extends PowerMockTestCase {
@Test
public void mockSingleton() {
final int expectedScore = 120;
PowerMockito.mockStatic(SingletonScoreGrader.class);
SingletonScoreGrader singletonMock = Mockito.mock(SingletonScoreGrader.class);
Mockito.doReturn(expectedScore).when(singletonMock).getScore();
Mockito.when(SingletonScoreGrader.instance()).thenReturn(singletonMock);
Assert.assertEquals(SingletonScoreGrader.instance().getScore(), expectedScore);
}
}
要模拟单例类,我们可以简单地创建一个类的模拟并模拟静态“instance”方法以返回该模拟。运行上述测试,我们会发现它成功完成。
除了“Mockito.doReturn()”,我们还可以使用“Mockito.doAnswer()”
在使用 Mockito 时,我们可以使用“Mockito.doReturn()”来模拟方法的行为并更改方法返回的对象。虽然它非常易于使用,“Mockito.doAnswer()”方法功能要强大得多。
package org.song.example;
import java.util.ArrayList;
import java.util.List;
import org.mockito.Mockito;
import org.mockito.invocation.InvocationOnMock;
import org.mockito.stubbing.Answer;
import org.powermock.api.mockito.PowerMockito;
import org.powermock.core.classloader.annotations.PrepareForTest;
import org.powermock.modules.testng.PowerMockTestCase;
import org.testng.Assert;
import org.testng.annotations.Test;
@PrepareForTest({AFinalClass.class})
public class DoAnswerTest extends PowerMockTestCase {
@Test
public void doAnswerTest() {
final String testInput = "A test input";
final String mockedResult = "Mocked final echo result - " + testInput;
AFinalClass aFinalClass_mock = PowerMockito.mock(AFinalClass.class);
final List<String> answers = new ArrayList<String>();
final String mockIsUsed = "The mock is used to generate the result";
Mockito.doAnswer(new Answer<String>() {
@Override
public String answer(InvocationOnMock invocation) throws Throwable {
answers.add(mockIsUsed);
return mockedResult;
}
}).when(aFinalClass_mock).echoString(testInput);
// Assert the mocked result is returned from method call
Assert.assertEquals(aFinalClass_mock.echoString(testInput), mockedResult);
// In addition to the mocked result, we can keep additional information of
// the calling of the mock and add complex logic in the mock
Assert.assertEquals(answers.size(), 1);
Assert.assertEquals(answers.get(0), mockIsUsed);
}
}
- “Mockito.doAnswer()”方法具有与“Mockito.doReturn()”相同的能力,可以指定方法预期的模拟结果;
- 它之所以更强大,是因为它允许我们定义一个真实的方法来控制模拟结果的生成并保留被模拟方法的调用历史。
运行上面的测试,我们可以看到以下结果。
Surefire 中的测试监听器
这个主题与 Mockito 没有直接关系,但可能对单元测试有帮助。我们可能希望在任何单元测试用例开始之前执行一些操作,例如初始化测试数据库,这并不少见。如果这些操作失败,我们希望失败并以失败状态退出单元测试。这可以通过Surefire 监听器轻松完成。我们可以在 POM 中配置监听器,如下所示
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>${surefire.version}</version>
<configuration>
<properties>
<property>
<name>listener</name>
<value>org.song.example.MyRunListener</value>
</property>
</properties>
<systemPropertyVariables>
<P1>P1 value</P1>
<P2>P2 value</P2>
</systemPropertyVariables>
</configuration>
</plugin>
除了添加监听器,我们还在 Surefire 配置中添加了一些“systemPropertyVariables”。“MyRunListener”实现如下
package org.song.example;
import org.testng.Assert;
import org.testng.ITestContext;
import org.testng.ITestListener;
import org.testng.ITestResult;
public class MyRunListener implements ITestListener {
public void onTestStart(ITestResult result) {}
public void onTestSuccess(ITestResult result) {}
public void onTestFailure(ITestResult result) {}
public void onTestSkipped(ITestResult result) {}
public void onTestFailedButWithinSuccessPercentage(ITestResult result) {}
public void onStart(ITestContext context) {
System.out.println("Test Started globally - "
+ System.getProperty("P1") + " - " + System.getProperty("P2"));
Assert.fail("Artificially failed the test");
}
public void onFinish(ITestContext context) {}
}
“MyRunListener”实现了“ITestListener”接口,该接口定义了监听器可以监听的许多事件,但“MyRunListener”为了简单起见,只对“onStart”事件采取行动。运行单元测试后,我们可以看到以下结果。
- “systemPropertyVariables”部分中配置的值由代码打印出来;
- 单元测试失败是因为我们断言了一个人为的失败。正如预期的那样,这个失败也在任何测试用例开始之前退出了单元测试。
抑制不期望的行为和 WhiteBox
与其创建自己的示例,我不如在此处简单添加引用链接。在模拟某些对象时,我们可能会发现以下链接很有用,有时甚至至关重要。
- https://code.google.com/p/powermock/wiki/SuppressUnwantedBehavior;
- https://code.google.com/p/powermock/wiki/BypassEncapsulation.
使测试类可供其他模块使用
这并不常见,但有时您可能希望使一个模块中的测试类可供其他模块使用。默认情况下,Maven 不会将测试类包含在包中,但您可以在 POM 文件中添加以下部分。
<plugins>
<!-- .... other plugins -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<executions>
<execution>
<goals><goal>test-jar</goal></goals>
</execution>
</executions>
</plugin>
</plugins>
在模块成功构建后,我们应该在“target”文件夹中有两个 jar 文件。其中一个 jar 文件是模块中功能类的常规 jar 文件,另一个将打包测试类。要在其他模块中使用测试 jar 文件,我们可以添加以下依赖项。
<dependency>
<groupId>the-group-id</groupId>
<artifactId>the-artifact-id-of-the-module</artifactId>
<version>the-version</version>
<type>test-jar</type>
<scope>test</scope>
</dependency>
依赖作用域是“test”,因此测试类仅对依赖模块中的测试类可用,并且它不是 传递的。
过多的内存使用
如果您的单元测试占用过多内存,Maven 可能会无法完成测试。在这种情况下,您可以使用以下命令为测试分配更多内存。
mvn clean install -DargLine="-Xmx4096m"
正确扩展“PowerMockTestCase”的方法
根据 PowerMock 文档,“安全”地告诉 TestNG 使用 PowerMock 的方法是让测试类继承“org.powermock.modules.testng”包中的“PowerMockTestCase”类。这很好,但有一个技巧。我从经验中学到的是,我们永远不应该让一个抽象类继承“PowerMockTestCase”。如果我们这样做,TestNG 可能会失败,而Surefire 将不会告诉我们确切的问题所在以及原因。
关注点
- 本文档提供了两个正在运行的 Maven 示例项目,用于在 Java 单元测试中使用 PowerMockito 来模拟 final 和 static 方法;
- PowerMock 可以与 EasyMock 或 Mockito 一起使用。本文档仅展示 PowerMockito 的用法;
- 有一些讨论建议避免在 Java 代码中使用 final 和 static 方法,以使其更易于单元测试。但有时,我们可能需要模拟第三方 Java 代码,而我们没有选择绕过 final 和 static 方法,而且 final 和 static 方法在面向对象原则中有其不可或缺的价值;
- 我希望您喜欢我的文章,希望本文能以某种方式帮助您。
历史
首次修订 - 2014/8/14,修订 - 2014/9/8