Mockito 模拟静态方法 - PowerMock

Mockito 允许我们创建模仿对象. 由于静态方法属于类,所以在 Mockito 中没有办法模仿静态方法. 然而,我们可以使用 PowerMock 和 Mockito 框架来模仿静态方法。

Mockito Mock 静态方法使用 PowerMock

PowerMock提供不同的模块来扩展 [Mockito 框架]( / 社区 / 教程 / mockito - 教程)并运行 JUnit 和 TestNG 测试案例. 请注意, PowerMock 尚未支持 [JUnit 5]( / 社区 / 教程 / junit5- 教程),因此我们将创建 JUnit 4 测试案例。

PowerMock 依赖

我们需要遵循PowerMock依赖性来嘲笑Mockito中的静态方法。

  • powermock-api-mockito2:这是核心的PowerMock依赖性,用于扩展Mockito2模仿框架。如果您正在使用Mockito 1.x版本,则使用‘powermock-api-mockito’模块
  • powermock-module-junit4:使用PowerMock运行 JUnit 4测试案例
  • powermock-module-testng:运行TestNG测试案例并支持PowerMock

下面是我们项目的最终pom.xml。

  1<project xmlns="https://maven.apache.org/POM/4.0.0"
  2    xmlns:xsi="https://www.w3.org/2001/XMLSchema-instance"
  3    xsi:schemaLocation="https://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
  4    <modelVersion>4.0.0</modelVersion>
  5    <groupId>com.journaldev.powermock</groupId>
  6    <artifactId>PowerMock-Examples</artifactId>
  7    <version>0.0.1-SNAPSHOT</version>
  8
  9    <properties>
 10    	<testng.version>6.14.3</testng.version>
 11    	<junit4.version>4.12</junit4.version>
 12    	<mockito-core.version>2.19.0</mockito-core.version>
 13    	<powermock.version>2.0.0-beta.5</powermock.version>
 14    	<java.version>10</java.version>
 15    </properties>
 16
 17    <dependencies>
 18    	<!-- TestNG -->
 19    	<dependency>
 20    		<groupId>org.testng</groupId>
 21    		<artifactId>testng</artifactId>
 22    		<version>${testng.version}</version>
 23    		<scope>test</scope>
 24    	</dependency>
 25    	<!-- JUnit 4 -->
 26    	<dependency>
 27    		<groupId>junit</groupId>
 28    		<artifactId>junit</artifactId>
 29    		<version>${junit4.version}</version>
 30    		<scope>test</scope>
 31    	</dependency>
 32    	<!-- Mockito 2 -->
 33    	<dependency>
 34    		<groupId>org.mockito</groupId>
 35    		<artifactId>mockito-core</artifactId>
 36    		<version>${mockito-core.version}</version>
 37    		<scope>test</scope>
 38    	</dependency>
 39    	<!-- PowerMock TestNG Module -->
 40    	<dependency>
 41    		<groupId>org.powermock</groupId>
 42    		<artifactId>powermock-module-testng</artifactId>
 43    		<version>${powermock.version}</version>
 44    		<scope>test</scope>
 45    	</dependency>
 46    	<!-- PowerMock JUnit 4.4+ Module -->
 47    	<dependency>
 48    		<groupId>org.powermock</groupId>
 49    		<artifactId>powermock-module-junit4</artifactId>
 50    		<version>${powermock.version}</version>
 51    		<scope>test</scope>
 52    	</dependency>
 53    	<!-- PowerMock Mockito2 API -->
 54    	<dependency>
 55    		<groupId>org.powermock</groupId>
 56    		<artifactId>powermock-api-mockito2</artifactId>
 57    		<version>${powermock.version}</version>
 58    		<scope>test</scope>
 59    	</dependency>
 60    </dependencies>
 61    <build>
 62    	<plugins>
 63    		<plugin>
 64    			<artifactId>maven-compiler-plugin</artifactId>
 65    			<version>3.7.0</version>
 66    			<configuration>
 67    				<source>${java.version}</source>
 68    				<target>${java.version}</target>
 69    			</configuration>
 70    		</plugin>
 71    		<plugin>
 72    			<groupId>org.apache.maven.plugins</groupId>
 73    			<artifactId>maven-surefire-plugin</artifactId>
 74    			<version>2.22.0</version>
 75    			<dependencies>
 76    				<dependency>
 77    					<groupId>org.apache.maven.surefire</groupId>
 78    					<artifactId>surefire-junit47</artifactId>
 79    					<version>2.22.0</version>
 80    				</dependency>
 81    				<dependency>
 82    					<groupId>org.apache.maven.surefire</groupId>
 83    					<artifactId>surefire-testng</artifactId>
 84    					<version>2.22.0</version>
 85    				</dependency>
 86    			</dependencies>
 87    			<configuration>
 88    				<additionalClasspathElements>
 89    					<additionalClasspathElement>src/test/java/</additionalClasspathElement>
 90    				</additionalClasspathElements>
 91    				<!-- TestNG Test Fails when executed from command line with message
 92    					"Cannot use a threadCount parameter less than 1" 
 93    					Works when threadCount is explicitly specified 
 94    					https://gist.github.com/juherr/6eb3e93e2db33979b7e90b63ddadc888-->
 95    				<threadCount>5</threadCount>
 96    			</configuration>
 97    		</plugin>
 98    	</plugins>
 99    </build>
100</project>

请注意,我正在使用2.0.0-beta.5版本的PowerMock. 但是,这个版本支持Java 10,它仍然处于测试阶段,所以在复杂情况下可能存在一些问题. 当我尝试使用当前的稳定版本1.7.x,我收到以下错误。

1java.lang.NoSuchMethodError: org.mockito.internal.handler.MockHandlerFactory.createMockHandler(Lorg/mockito/mock/MockCreationSettings;)Lorg/mockito/internal/InternalMockHandler;
2    at org.powermock.api.mockito.internal.mockcreation.DefaultMockCreator.createMethodInvocationControl(DefaultMockCreator.java:114)
3    at org.powermock.api.mockito.internal.mockcreation.DefaultMockCreator.createMock(DefaultMockCreator.java:69)
4    at org.powermock.api.mockito.internal.mockcreation.DefaultMockCreator.mock(DefaultMockCreator.java:46)
5    at org.powermock.api.mockito.PowerMockito.mockStatic(PowerMockito.java:73)

以下是为此例外打开的 GitHub 问题 - issue1issue2

1package com.journaldev.mockito.staticmethod;
2
3public class Utils {
4
5    public static boolean print(String msg) {
6    	System.out.println("Printing "+msg);
7    	return true;
8    }
9}

JUnit Mockito PowerMock 示例

我们需要做以下操作来整合 PowerMock 与 Mockito 和 JUnit 4。

  • @RunWith(PowerMockRunner.class) 注释的测试类
  • @PrepareForTest 注释测试类,并使用 PowerMock.
  • 使用 PowerMockito.mockStatic() 以使用静态方法进行模仿类
  • 使用 PowerMockito.verifyStatic() 以使用 Mockito. 验证模仿方法

以下是使用Mockito和PowerMock在JUnit测试案例中嘲笑静态方法的完整示例。

 1package com.journaldev.mockito.staticmethod;
 2
 3import static org.junit.Assert.assertFalse;
 4import static org.junit.Assert.assertTrue;
 5import static org.mockito.ArgumentMatchers.anyString;
 6import static org.mockito.Mockito.atLeast;
 7import static org.mockito.Mockito.when;
 8
 9import org.junit.Test;
10import org.junit.runner.RunWith;
11import org.powermock.api.mockito.PowerMockito;
12import org.powermock.core.classloader.annotations.PrepareForTest;
13import org.powermock.modules.junit4.PowerMockRunner;
14
15@RunWith(PowerMockRunner.class)
16@PrepareForTest(Utils.class)
17public class JUnit4PowerMockitoStaticTest{
18
19    @Test
20    public void test_static_mock_methods() {
21    	PowerMockito.mockStatic(Utils.class);
22    	when(Utils.print("Hello")).thenReturn(true);
23    	when(Utils.print("Wrong Message")).thenReturn(false);
24    	
25    	assertTrue(Utils.print("Hello"));
26    	assertFalse(Utils.print("Wrong Message"));
27    	
28    	PowerMockito.verifyStatic(Utils.class, atLeast(2));
29    	Utils.print(anyString());
30    }
31}

Mockito PowerMock 示例

对于 TestNG 测试案例,我们不需要使用@RunWith注释,我们需要测试类来扩展PowerMockTestCase,以便使用PowerMockObjectFactory创建测试类实例。

 1package com.journaldev.mockito.staticmethod;
 2
 3import static org.testng.Assert.assertFalse;
 4import static org.testng.Assert.assertTrue;
 5
 6import static org.mockito.Mockito.*;
 7import org.powermock.api.mockito.PowerMockito;
 8import org.powermock.core.classloader.annotations.PrepareForTest;
 9import org.powermock.modules.testng.PowerMockTestCase;
10import org.testng.annotations.Test;
11
12@PrepareForTest(Utils.class)
13public class TestNGPowerMockitoStaticTest extends PowerMockTestCase{
14
15    @Test
16    public void test_static_mock_methods() {
17    	PowerMockito.mockStatic(Utils.class);
18    	when(Utils.print("Hello")).thenReturn(true);
19    	when(Utils.print("Wrong Message")).thenReturn(false);
20    	
21    	assertTrue(Utils.print("Hello"));
22    	assertFalse(Utils.print("Wrong Message"));
23    	
24    	PowerMockito.verifyStatic(Utils.class);
25    	Utils.print("Hello");
26    	PowerMockito.verifyStatic(Utils.class, times(2));
27    	Utils.print(anyString());
28    }
29}

摘要

PowerMock为Mockito提供了扩展的功能,其中之一是测试静态方法的能力,它可以很容易地集成到 JUnit 4 和 TestNG。

您可以从我们的 GitHub 存储库下载完整的项目。

Published At
Categories with 技术
Tagged with
comments powered by Disqus