多线程环境中使用 Mockito 来 Mock 静态方法

回看三年前的一篇日志 Mockito 3.4.0 开始可 Mock  静态方法,最后对 Mockito 产生的缺憾是它无法用来 Mock 非测试线程(主线程)中的静态方法调用。其实这也是可以变通的,下面慢慢道来。

首先回顾一下 Mockito  的静态方法 Mock 的使用方法,随着 Mockito 版本的升级,引入依赖的方式也发生了些许的变化,以 Maven 项目为例,如果在 JUnit 5 下用 Mockito 的 pom.xml 依赖中为

由它引入的全部相关依赖

如今不再使用 mockito-inline 依赖了,以及它的 mockito-extensions/org.mockito.plugins.MockMaker(mock-make-inline) 和 mockito-extensions/org.mockito.plugins.MemberAccessor(memer-accessor-module)。

测试代码

Mock 了静态方法 LocalDate.of(year, month, day), 所以在 try(MockedStatic) 块中无论传入什么参数给 LocalDate.of() 方法返回的都是 1970-01-01

try(MockedStatic) 块只对它所在的线程起作用,如果 LocalDate.of() 是在其他线程中调用就无能为力了。

比如用下方的代码演示非主线程(测试线程)中调用 LocalDate.of()时不能被 Mock 的效果

这个测试就会失败了

MockitoDemoTest.testMockitoMockStatic:49 expected: <1970> but was: <2024>

不过实际应用中我们多用线程池,不是说 try(MockedStatic) 只对它所在的线程起作用吗,那么我们可以对线程池来个腾龙换鸟,把主线程作为线程池中的唯一线程,这样所有的代码都会在 try(MockedStatic) 所在的线程(主线程)中执行了。

为演示全过程,先创建一个待测试的类 MockitoDemo

如果不管不顾线程池的角色,写如下的测试代码

测试也将无法通过

MockitoDemoTest.testMockitoMockStatic:46 expected: <1970> but was: <2024>

变通要来了,针对线程池下手,用当前线程作为唯一线程的线程池替代它就行,完整的实现是

测试通过

主要的行为就是覆盖了 execute(Runnable command) 方法,直接执行 command.run(), 所起的作用就是提交到 threadPool 的任务全部直接调用创建该 threadPool 实例的线程去执行,即实现了一个只有主线程(测试线程)的线程池,从而使得 try(MockedStatic) 与 MockitoDemo.getLocalDate() 中的 LocalDate.of(2024, 10, 10) 由同一个线程执行。

话外

Maven 中使用当前的 Mockito 5.14.1 版本时,运行 mvn test 会看到如下控制台输出

Mockito is currently self-attaching to enable the inline-mock-maker. This will no longer work in future releases of the JDK. Please add Mockito as an agent to your build what is described in Mockito's documentation: https://javadoc.io/doc/org.mockito/mockito-core/latest/org/mockito/Mockito.html#0.3

此篇测试用的 JDK 版本为 21, 参考信息所指引的链接 https://javadoc.io/doc/org.mockito/mockito-core/latest/org/mockito/Mockito.html#0.3,在 pom.xml 中加上

再次运行 mvn test, 提示信息便消失了。

本文链接 https://yanbin.blog/mockito-mock-static-method-in-multiple-threading-env/, 来自 隔叶黄莺 Yanbin Blog

[版权声明] Creative Commons License 本文采用 署名-非商业性使用-相同方式共享 4.0 国际 (CC BY-NC-SA 4.0) 进行许可。

Subscribe
Notify of
guest

0 Comments
Inline Feedbacks
View all comments