Reputation: 16235
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?
Upvotes: 2
Views: 204
Reputation: 20395
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);
Upvotes: 2