一尘不染

Mockito:监视功能接口内部的函数调用?

spring-boot

Mockito似乎无法监视Functional接口内部的函数调用。假设我有一个带有服务的简单Spring Boot应用程序:

@Service
public class TestService {

    Function<Integer, Integer> mapping = this::add2;

    Integer add2(Integer integer) {
        return integer + 2;
     }

}

并进行测试:

@SpyBean
TestService testService;

@Test
public void mockitoTest2(){

    doReturn(6).when(testService).add2(2);

    System.out.println(testService.mapping.apply(2));

}

测试将返回4而不是6。这是预期的还是值得进行错误报告?


阅读 343

收藏
2020-05-30

共1个答案

一尘不染

这是预期的。Mockito通过创建 浅表副本 来创建间谍,并且this::add2在保留对旧引用的同时复制方法引用this

TestService myTestService = new TestService();
TestService mySpy = Mockito.spy(myTestService);

在此示例中,mySpyTestService生成的子类的实例
,该类具有重写的所有可重写方法以委托给Mockito,并且其所有实例状态都从浅层复制myTestService。这意味着myTestService.mapping == mySpy.mapping,这也意味着复制了对this(意义myTestService)的引用。

应用于实例的方法引用捕获该实例,如“方法引用的种类”下“方法引用”
的Oracle页面上所示。接收add2呼叫的对象是原始对象,而不是间谍,因此您得到的是原始行为(4),而不是受到间谍影响的行为(6)。

这应该有点直观:您可以在Function<Integer, Integer>不传递TestService实例的情况下调用,因此,该Function包含对TestService实现的隐式引用是很合理的。您看到这种现象的原因是,在初始化并存储功能
,间谍实例的状态会从真实实例中复制this


考虑可以在TestService上定义的替代方法:

BiFunction<TestService, Integer, Integer> mapping2 = TestService::add2;

在这里,该函数mapping2不适用于特定对象,而是适用于传入的TestService的任何实例。因此,您的测试将调用此方法:

@Test
public void mockitoTest2(){
    doReturn(6).when(testService).add2(2);
    System.out.println(testService.mapping2.apply(testService, 2));
}

…并且因为您传入了间谍testService,它将处理对的虚拟方法调用add2并调用间谍上设置的行为(返回6)。没有隐式保存this的功能,因此您的功能可以按预期工作。

2020-05-30