用Mockito模拟静态方法的教程

10,264 阅读3分钟

学习在Java单元测试中使用Mockito静态方法进行模拟。以前,我们必须使用PowerMock来模拟私有和静态方法,但从3.4.0版本开始,Mockito支持直接模拟静态方法

1.1.Maven的依赖性

为了模拟静态方法,我们需要使用mockito-inline模块提供的内联模拟工具。请注意,这个模块在一段时间内是独立于mockito-core 模块的,在未来的版本中,它将与mockito-core本身合并。

mockito-inline模块是为社区反馈而单独开发的,它为static 方法提供了嘲讽功能;以及final 类和方法,这些方法以前被认为是不可嘲讽的。它同时使用了Java工具化API和子类的组合,而不是创建一个新的类来代表一个模拟。

<dependency>
    <groupId>org.mockito</groupId>
    <artifactId>mockito-inline</artifactId>
    <version>4.6.1</version>
    <scope>test</scope>
</dependency>

2.被测系统

为了演示的目的,我们正在创建一个有两个方法的简单类。

  • 第一个方法不接受任何参数,并返回字符串值 "foo"。
  • 第二个方法接受一个可变数量的int参数,并返回它们的总和。
class ClassWithStaticMethod {

  public static String getVal() {
    return "foo";
  }

  public static int add(int... args) {
    return IntStream.of(args).sum();
  }
}

3.MockedStatic

MockedStatic表示对一个类型的静态方法主动和范围的模拟。由于静态模拟的定义范围,一旦范围被释放,它就会返回到它的原始行为。为了定义模拟行为和验证静态方法的调用,使用从Mockito.mockStatic() 方法返回的MockedStatic引用。

有必要调用ScopedMock.close() 方法来释放静态模拟,一旦它被使用并且不再需要。因此,建议在try-with-resources语句中创建这个对象,除非是明确管理。

下面是在单元测试中使用MockedStatic类的语法。

try (MockedStatic mock = mockStatic(AppStatic.class)) {
  //record mock expectations
  //test code
  //verify mock
}

如果我们不使用try-with-resources块,正如建议的那样,嘲讽/存根/验证将如期进行,但会使该类处于被嘲讽的状态。

3.嘲弄没有错误的静态方法

让我们来模拟第一个方法getVal() ,该方法不需要参数并返回一个字符串值"foo" 。我们正在模拟getVal() 方法并从模拟中返回值"bar"

当我们调用getVal() 方法时,在模拟范围之外,我们应该得到*"bar "的值,而在范围之内,我们应该得到"foo "的值。*

@Test
public void testGetVal() {
	//Outside scope
  assertEquals("foo", ClassWithStaticMethod.getVal());

  try (MockedStatic mockStatic = mockStatic(ClassWithStaticMethod.class)) {

    mockStatic.when(ClassWithStaticMethod::getVal).thenReturn("bar");

    //Inside scope
    assertEquals("bar", ClassWithStaticMethod.getVal());
    mockStatic.verify(ClassWithStaticMethod::getVal);
  }

  //Outside scope
  assertEquals("foo", ClassWithStaticMethod.getVal());
}

4.嘲弄一个有参数的静态方法

对接受参数和返回值的静态方法的嘲弄与上一节基本相同。此外,我们可以在期望中使用灵活的参数匹配器。

请注意,我们使用lambda表达式的语法来调用静态方法

@Test
public void testAdd() {
  assertEquals(3, ClassWithStaticMethod.add(1, 2));

  try (MockedStatic mockStatic = mockStatic(ClassWithStaticMethod.class)) {

    mockStatic.when(() -> ClassWithStaticMethod.add(anyInt(), anyInt())).thenReturn(10);

    assertEquals(10, ClassWithStaticMethod.add(1, 2));
    mockStatic.verify(() -> ClassWithStaticMethod.add(1, 2));
  }

  assertEquals(3, ClassWithStaticMethod.add(1, 2));
}

5.总结

在本教程中,我们学习了如何创建、记录期望值并验证mocks是否有静态方法。请确保你理解这样一个事实,即静态mock被期望在定义的范围内使用,模块mockito-inline可以在未来与mockito-core合并。

学习愉快!!

源代码在Github上