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

时间:2018-09-17 15:08:46

标签: spring-boot mockito functional-interface

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。这是预期的还是值得进行错误报告?

1 个答案:

答案 0 :(得分:2)

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

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

在此示例中,mySpy TestService生成的子类的实例,该子类的所有可覆盖方法都被重写以委派给Mockito,并且其所有实例状态都浅从myTestService复制。这意味着myTestService.mapping == mySpy.mapping(这也意味着对this的引用(意味着myTestService)在函数中被捕获了。

应用于实例的方法引用捕获该实例,如the Oracle page on Method References下“方法引用的种类”下。收到add2调用的对象是原始对象,而不是间谍,因此您得到的是原始行为(4),而不是受到间谍影响的行为(6)。

这应该有点直观:您可以在不传递TestService实例的情况下调用Function<Integer, Integer>,因此,该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,因此您的函数可以按预期工作。

另请参见: Mockito runnable: wanted but not invoked?