alibaba / testable-mock

换种思路写Mock,让单元测试更简单
https://alibaba.github.io/testable-mock/
MIT License
1.83k stars 310 forks source link

把Mock类移到另外的包中,代理规则就变了 #299

Open lihuachuan opened 2 years ago

lihuachuan commented 2 years ago

我git了源码,jdk改为1.8 把CookerServiceMock改为public,然后运行了java-demo中的SellerServiceTest,正常测试通过

但是当我把CookerServiceMock移到com.alibaba.demo.mock包下, 在SellerServiceTest中加了@MockWith(CookerServiceMock.class), 然后神奇的事情发生了,should_sell_sandwich测试失败

org.opentest4j.AssertionFailedError: 
Expected :Fake-Sandwich-Cooker & Faked-Sandwich
Actual   :Real-Sandwich-Cooker & Real-Sandwich

我查看了日志,hireSandwichCooker和cookSandwich没有used的记录

后来我测试了一下,当我在代码中加入

@MockInvoke(targetClass = CookerService.class)
private String prepareSandwich() {
        return "prepareSandwich";
}

prepareSandwich有used日志

所以代理的规则是怎么样的,什么时候替换是生效,嵌套调用的生效范围是?

linfan commented 1 year ago

抱歉近期issue维护频率比较低,耽搁了较长时间。

刚开始看完描述,没有Get到问题在哪里,最近抽空按照你的描述实际操作了一下,理解你的困惑点了。

从原理来说,Testable其实只需要让每个被测类能找到特定一批Mock方法,然后在测试运行期间自动将被测类里匹配到的调用换成对Mock方法的调用就达到目的了。因此虽然说是三个类相互关联,在大多数情况下,只要有被测类->Mock类这条关联就足够了,被测类->测试类的关联主要是为了便于建立前一条关联(通常Mock类作为测试类的内部类),而测试类->Mock类的关联只在使用到MockScope等特定能力的时候才是必须的。

Testable遵循“约定大于配置”的原则,因此当包路径和Mock类名符合约定的时候,一切过程都会很自然的发生(相关命名规则见文档)。当包路径不一致的时候,就需要用到@MockWith注解。这时候,为了尽可能的避免在被测类代码上增加额外的与测试相关的注解,因此Testable约定只需要将@MockWith加到测试类上,也能对相应的被测类起作用(直接把@MockWith加到被测类上,也能起到同样效果,但这样需要将testable在pom.xml的引用范围从test改为default)。

以上就是所有的规则。

回到上面的问题,当CookerServiceMock类被移动到了非约定的目录位置,此时被测类CookerService和测试类SellerServiceTest都无法找到自己关联的Mock类了。然后给SellerServiceTest类加上了@MockWith注解,会使得测试类SellerServiceTest与它的被测类SellerService都关联到Mock类CookerServiceMock上,但原本的被测类CookerService依然无法找到自己要关联的Mock类,因此测试失败,并且当再增加对发生在SellerService类中的prepareSandwich()调用的Mock方法时,该Mock能够生效。