昨天天去github上的PowerMock 项目去看了一下。这个项目上次的commit和发布已经是10个月之前了。还积攒了400个问题和13个PR没有合并。当然,作为一个出道很久的小众Mock工具的项目,本身的活跃度低也是比较正常的。不过,很多Issue其实是关于新JDK兼容性的。从这点上看,维护者已经不是在积极维护这个项目了。
而造成这些问题的一个重要因素,其实和JUnit5有关。
众所周知,Mockito采用的是所谓动态代理的方式来实现mocking的,这种机制也因此让Mockito无法去模拟 静态或者final的类型或者方法(2.0之前),否则会出现类似以下的错误:
you stub either of: final/private/equals()/hashCode() methods.
Those methods *cannot* be stubbed/verified.
Mocking methods declared on non-public parent classes is not supported.
这类的需求催生了PowerMock这样强大的模拟工具,可以通过自定义的类加载器来实现上述需求。因此,在JUnit4的时代,Mockito+PowerMock成为了一个单元测试模拟工具的黄金搭档。
然而,当JUnit5问世之后,作为Java单元测试框架的默认选择,PowerMock积极主动拥抱JUnit5。然而这样的姿态,并没有打动Junit团队。早在2016年,在JUnit5尚未正式发布时,PowerMock团队就对JUnit团队提出了兼容PowerMock的需求:
指出由于Junit5不允许客制化的类加载器,因此JUnit4中通过Rule机制进行Mock类加载的PowerMock MockClassLoader无法在JUnit5中直接使用,需要JUnit团队对JUnit5进行修改。
而JUnit团队认为PowerMock的实现机制侵入性太强,并且属于小众需求,因此该需求历时5年多了一直没有实现。
Mockito的乘势而入
而Mockito团队则看到了这个机会,实现了Mockito功能的突破,进入了原先PowerMock的领域。根据Mockito.org的说法,Mockito从2.1支持mock final类型和方法。Rafael Winterhalter在Mockito 2.1.0版本里创建了一种叫做Inline mock maker的 mock方法,突破了上述限制。并且从Mockito2.7.6版本开始,可以不再需要添加配置文件而只需要在project POM中用”mockito-inline”的artifact替换掉”mockto-core”的artifact,就直接使用免配置的inline mock making。
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-inline</artifactId>
<version>3.3.3</version>
</dependency>
不过根据目前的官网说明,该特性仍旧处于向社区征求意见的阶段。如果最终该子项目成熟,被吸收进Mockito的正式项目,依托Mockito-core项目的巨大下载量,以及在SpringBoot-test-starter中的默认mock框架的优势,这个项目还是有取代PowerMock的机会。
于是,这对在Junit4时代的黄金搭档,终于还是在JUnit5时代分道扬镳,各奔前程了。感兴趣的读者可以到Junit5项目中为PowerMock团队的这个需求投票,协助PowerMock团队拿到通向未来的船票。只是这艘渐行渐远的船上,早就有了新的明星。
“Old soldiers never die, they just fade away”