一、当需要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";
    }
}

 

  1. 添加依赖
    让我们开始将mockito-inline依赖项添加到我们的pom.xml
<dependency>
    <groupId>org.mockito</groupId>
    <artifactId>mockito-inline</artifactId>
    <version>3.8.0</version>
    <scope>test</scope>
</dependency>
  1. 模拟无参静态方法
@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 不需要为每个测试替换类加载器。

  1. 用参数模拟静态方法
    现在让我们看看另一个常见的用例,当我们需要模拟一个有参数的方法时:
@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 表达式,我们在其中指定方法以及我们想要模拟的任何参数。