一、当需要mock静态方法的时候,必须加注解@PrepareForTest和@RunWith。注解@PrepareForTest里写的类是静态方法所在的类。
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; import static org.junit.Assert.assertEquals; import static org.mockito.Matchers.eq; @RunWith(PowerMockRunner.class) @PrepareForTest(String.class) public class MockPrepareForTest { @Test public void testStaticMathod () { TestString testString = new TestString(); PowerMockito.mockStatic(String.class); PowerMockito.when(String.valueOf(eq(100l))).thenReturn("TEST"); String result = testString.getTestString(100l); assertEquals("TEST", result); } class TestString { public String getTestString(long number) { return String.valueOf(number); } } }
以上模拟静态方法的方式仅适用于JDK8 以下的版本,如果你想在JDK8+的版本模拟静态方法,可以用以下的方式。
二、使用最新版本的 Mockito 模拟静态方,我们测试的重点将是一个简单的静态实用程序类:
public class StaticUtils { private StaticUtils() {} public static List<Integer> range(int start, int end) { return IntStream.range(start, end) .boxed() .collect(Collectors.toList()); } public static String name() { return "Baeldung"; } }
- 添加依赖
让我们开始将mockito-inline依赖项添加到我们的pom.xml:
<dependency> <groupId>org.mockito</groupId> <artifactId>mockito-inline</artifactId> <version>3.8.0</version> <scope>test</scope> </dependency>
- 模拟无参静态方法
@Test void givenStaticMethodWithNoArgs_whenMocked_thenReturnsMockSuccessfully() { assertThat(StaticUtils.name()).isEqualTo("Baeldung"); try (MockedStatic<StaticUtils> utilities = Mockito.mockStatic(StaticUtils.class)) { utilities.when(StaticUtils::name).thenReturn("Eugen"); assertThat(StaticUtils.name()).isEqualTo("Eugen"); } assertThat(StaticUtils.name()).isEqualTo("Baeldung"); }
如前所述,从 Mockito 3.4.0 开始,我们可以使用Mockito.mockStatic( Class<T> classToMock )方法来模拟对静态方法调用的调用。此方法为我们的类型返回一个MockedStatic对象,它是一个作用域模拟对象。
因此,在我们上面的单元测试中,utilities变量表示具有线程局部显式作用域的模拟。需要注意的是,作用域模拟必须由激活模拟的实体关闭。这就是为什么我们在try-with-resources构造中定义我们的模拟,以便当我们完成我们的作用域块时模拟会自动关闭。
这是一个特别好的功能,因为它确保我们的静态模拟保持临时。正如我们所知,如果我们在测试运行期间使用静态方法调用,由于运行测试的并发和顺序特性,这可能会对我们的测试结果产生不利影响。
最重要的是,另一个很好的副作用是我们的测试仍然会运行得非常快,因为 Mockito 不需要为每个测试替换类加载器。
- 用参数模拟静态方法
现在让我们看看另一个常见的用例,当我们需要模拟一个有参数的方法时:
@Test void givenStaticMethodWithArgs_whenMocked_thenReturnsMockSuccessfully() { assertThat(StaticUtils.range(2, 6)).containsExactly(2, 3, 4, 5); try (MockedStatic<StaticUtils> utilities = Mockito.mockStatic(StaticUtils.class)) { utilities.when(() -> StaticUtils.range(2, 6)) .thenReturn(Arrays.asList(10, 11, 12)); assertThat(StaticUtils.range(2, 6)).containsExactly(10, 11, 12); } assertThat(StaticUtils.range(2, 6)).containsExactly(2, 3, 4, 5); }
在这里,我们遵循相同的方法,但这次我们在我们的when子句中使用lambda 表达式,我们在其中指定方法以及我们想要模拟的任何参数。