1.概述
通常,在编写单元测试时,我们会遇到需要模拟静态方法的情况。在Mockito的3.4.0版本之前,不可能直接模拟静态方法–仅在PowerMockito的帮助下。
在本教程中,我们将研究如何使用最新版本的Mockito模拟静态方法。要了解有关使用Mockito进行测试的更多信息,请查看我们全面的Mockito系列。
2.一个简单的静态实用程序类
在整个教程中,我们测试的重点将是一个简单的静态实用程序类:
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 "1ju.org";
}
}
为了演示的目的,我们有一个方法带有一些参数,而另一种方法仅返回String
。
3.依存关系
让我们开始吧,向我们的pom.xml
mockito-inline
依赖项:
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-inline</artifactId>
<version>3.8.0</version>
<scope>test</scope>
</dependency>
值得注意的是,在某些时候,根据文档,此功能很可能已集成到更熟悉的mockito-core
依赖中。
4.快速测试静态方法
一般来说,有人可能会说,在编写干净的面向对象的代码时,我们不需要模拟静态类。这通常可能暗示我们的应用程序中存在设计问题或代码异味。
首先,因为依赖于静态方法的类具有紧密的耦合,其次,它几乎总是导致难以测试的代码。理想情况下,类不应负责获取其依赖项,并且如果可能的话,应该从外部注入它们。
因此,始终值得研究是否可以重构代码以使其更具可测试性。当然,这并非总是可能的,有时我们不得不模拟静态方法。
5.模拟一个无参数的静态方法
让我们继续前进,看看如何从StaticUtils
类中name
@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("1ju.org");
}
如前所述,自Mockito 3.4.0起,我们可以使用Mockito.mockStatic( Class<T> classToMock )
方法来模拟对静态方法调用的调用。此方法MockedStatic
对象,这是一个有范围的模拟对象。
因此,在上面的单元测试中, utilities
变量表示具有线程局部显式作用域的模拟。重要的是要注意,作用域模拟必须由激活该模拟的实体关闭。这就是为什么我们在try-with-resources构造中定义模拟程序的原因,以便当我们完成作用域块时自动关闭模拟程序。
这是一个特别不错的功能,因为它可以确保我们的静态模拟仍然是临时的。众所周知,如果在测试运行过程中使用静态方法调用,由于运行测试的并发性和顺序性,这很可能对测试结果造成不利影响。
最重要的是,另一个好处是我们的测试仍然可以超级快速地运行,因为Mockito不需要为每个测试都替换类加载器。
在我们的示例中,我们通过在作用域块之前和之后检查静态方法name
返回实值来再次重申这一点。
6.用参数模拟静态方法
现在,让我们看看需要模拟带有参数的方法时的另一个常见用例:
@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);
}
如我们所见,除了这次,我们使用了与lambda表达式相同的方法,除了这次,我们在when
子句中使用了lambda表达式。非常简单!
7.结论
在这篇快速的文章中,我们已经看到了一些示例,这些示例说明了如何使用Mockito模拟静态方法。总之,Mockito通过一个较小的lambda为狭窄的模拟静态对象提供了一种范围更广的解决方案。
0 评论