I have the following structure

public class A{...}

public class B extends A{
    private C cObject;
    private Object otherValue;

    B(){
       cObject = new C(this);
    }
}

public class C{
    private B bObject;

    C(B bObject){
       this.bObject = bObject;
    }
}

I want to test a method of the class B. I am using mockito because I need to mock another method of B in order to test the method I want to test. So In my test I declare the B object as @Spy, then I call MockitoAnnotations.initMocks(this); and finally I mock the method using doReturn().when().method();

Now I run the test and it fails. My surprise comes when I debug it and I realize that when I am in the object B, the value of the field otherValue is for example X but when I am in C, the value of this.bObject.otherValue is not X but null.

Since I've created the object C within B with new C(this);, shouldn't both B and C.bObject be the same object and contain therefore the same values?

NOTE: I've also tried it without spying the object and mocking the method and it works, so the real question is:

Does Mockito replace my object with another object when I spy it? And in that case, what can I do to make it work?

EDIT an easier explanation could be: I want to test an object B, this object B creates an instance of an object C passing itself (this) as parameter. I need to Spy the object B so I create in my test an instance of B and then call MockitoAnnotations.initMocks(this);. Are both objects (the one in the test and the one in the instance of C) after this calling still the same object or mockito replaced it with a new one?

有帮助吗?

解决方案

The B instance will be constructed before being spied, so the reference that C receives is the actual B object and not the spied instance.

You're adding behaviour to the spied instance which is indeed a different object to the one that C.bObject has, so the behaviour is not applied. Similarly setting b.otherValue will not result on b.cObject.bObject.otherValue being set.

You can see that these are different objects - assuming a default toString is present:

final B b = Mockito.spy(new B());

System.out.println("spied: " + b);
System.out.println("b.cObject.bObject: " + b.cObject.bObject);

It should produce something along the lines of:

spied: B$$EnhancerByMockitoWithCGLIB$$999ce15d@7a187814
b.cObject.bObject: B@5c73a7ab

Perhaps you could use reflection to set b.cObject.bObject field to the spied instance? For example:

final Field f = C.class.getDeclaredField("bObject");
f.setAccessible(true);
f.set(b.cObject, b);
许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top