I have class with inner class as following:
public class ClassWithInnerObject {
private final InnerObject innerObject;
public ClassWithInnerObject() {
innerObject = new InnerObject();
}
public void callInnerObjectMethod() {
innerObject.outerFunc();
}
public void outerFunc() {
innerFunc();
}
public void innerFunc() {
Log.d("XXX", "innerFunc: called");
}
public class InnerObject {
public void outerFunc() {
innerFunc();
}
}
}
And the mockito test is looking as following: build.gradle:
androidTestCompile 'junit:junit:4.12'
androidTestCompile 'org.mockito:mockito-core:1.10.19'
androidTestCompile 'com.crittercism.dexmaker:dexmaker:1.4'
androidTestCompile 'com.crittercism.dexmaker:dexmaker-mockito:1.4'
androidTestCompile 'com.crittercism.dexmaker:dexmaker-dx:1.4'
Test:
@RunWith(AndroidJUnit4.class) public class SpyVerifyTest {
@Test public void myInnerTestWorking() {
ClassWithInnerObject p = new ClassWithInnerObject();
ClassWithInnerObject spy = Mockito.spy(p);
spy.outerFunc();
verify(spy, times(1)).innerFunc();
}
@Test public void myInnerTestNotWorking() {
ClassWithInnerObject p = new ClassWithInnerObject();
ClassWithInnerObject spy = Mockito.spy(p);
spy.callInnerObjectMethod();
verify(spy, times(1)).innerFunc();
}
}
The first test is working as expected.
The second one the innerFunc
is never detected as "invoked", although in the log I see it is.What is wrong? :)
Thanks!
We can mock runInGround(String location) method inside the PersonTest class as shown below. Instead of using mock(class) here we need to use Mockito. spy() to mock the same class we are testing. Then we can mock the method we want as follows.
Simply put, the API is Mockito. spy() to spy on a real object. This will allow us to call all the normal methods of the object while still tracking every interaction, just as we would with a mock. Note how the real method add() is actually called and how the size of spyList becomes 2.
A mock does not call the real method, it is just proxy for actual implementations and used to track interactions with it. A spy is a partial mock, that calls the real methods unless the method is explicitly stubbed. Since Mockito does not mock final methods, so stubbing a final method for spying will not help.
Mockito spy() method Mockito provides a method to partially mock an object, which is known as the spy method. When using the spy method, there exists a real object, and spies or stubs are created of that real object. If we don't stub a method using spy, it will call the real method behavior.
What is wrong?
Well, the problem here is quite subtle, when you call Mockito.spy(p)
, mockito
creates behind the scene some kind of decorator over your instance of ClassWithInnerObject
allowing to monitor all methods calls on your instance. Thanks to that, you can check how many times a given method has been called but on the decorator only not on your instance. And here, when you use an inner class, it calls innerFunc()
on your instance of ClassWithInnerObject
not on the decorator so for Mockito
innerFunc()
has not been called.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With