一、当需要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 表达式,我们在其中指定方法以及我们想要模拟的任何参数。