简体   繁体   English

具有内部方法参考的Mockito Spying on Class

[英]Mockito Spying on Class that has an internal method reference

I'm seeing a different in behaviour when spying on a service using the @Spy annotation and having Mockito create the Server verses explicitly calling the constructor. 在使用@Spy注释监视服务并让Mockito创建显式调用构造函数的Server诗句时,我发现行为有所不同。

public class MyService {
    private final Supplier<String> methodBCall;

    public MyService() {
        methodBCall = this::methodB;
    }

    public void methodA() {
        methodBCall.get();
    }

    public String methodB() {
        return "methodB";
    }
}
@RunWith(MockitoJUnitRunner.class)
public class MyTest {

    @Spy
    private MyService myService1;
    @Spy
    private MyService myService2 = new MyService();

    @Test
    public void testSucceeds() {
        myService1.methodA();
        verify(myService1, times(1)).methodA();
        verify(myService1, times(1)).methodB();
    }

    @Test
    public void testFails() {
        myService2.methodA();
        verify(myService2, times(1)).methodA();
        verify(myService2, times(1)).methodB();
    }
}

The failing test fails with 测试失败的原因是

Wanted but not invoked:
myService2.methodB();
-> at com.phemi.services.policy.impl.MyTest.testFails

Why do these two behave differently? 为什么这两个行为不同? What is Mockito doing to initialize myService1 that enables it to spy on methodB? Mockito在初始化myService1使其能够监视methodB时在做什么?

This is a simplified example, in my case to test my service properly I need to call its constructor with an argument (and so cannot use the @Spy with a default constructor). 这是一个简化的示例,在本例中,为了正确测试我的服务,我需要使用参数调用其构造函数(因此不能将@Spy与默认构造函数一起使用)。 However, when I do that I cannot properly verify method calls. 但是,当我这样做时,我无法正确验证方法调用。

The spy on myService2 is only created after the object has been constructed, so having a method call in the constructor is not helpfull as it contains a method reference to the initial object (which is not the spy object). spymyService2对象已经被构造之后,所以具有在一个方法调用时才创建constructor并不有益的,因为它包含的方法参照初始对象(其不是spy对象)。

The difference becomes more evident when you compare the implementation for both cases: 当您比较两种情况的实现时,差异变得更加明显:

Mockito.spy(Class)

public static <T> T spy(Class<T> classToSpy) {
    return MOCKITO_CORE.mock(classToSpy, withSettings()
            .useConstructor()
            .defaultAnswer(CALLS_REAL_METHODS));
}

Mockito.spy(Object)

public static <T> T spy(T object) {
    return MOCKITO_CORE.mock((Class<T>) object.getClass(), withSettings()
            .spiedInstance(object)
            .defaultAnswer(CALLS_REAL_METHODS));
}

As you can see the first case, based on a class (which is used if no instance for @Spy was created), creates a mock first and uses the constructor on the mocked object. 如您所见,第一种情况基于一个类(如果未创建@Spy实例,则使用@Spy ),首先创建一个模拟并在模拟对象上使用构造函数。

In the second case the constructor is not considered instead a different instance is created. 在第二种情况下,不考虑构造函数,而是创建了一个不同的实例。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM