I have a java class (but I think java shouldn't matter, the issue should persist even given a scala implementation)
abstract class MyClass {
String fieldToCacheSerialization = null;
public String serialize() {
if(fieldToCacheSerialization == null) {
fieldToCacheSerialization = expensiveSerialization();
}
return fieldToCacheSerialization;
}
/** delegate to sub class implementation, but it is expensive operation
* and therefore we want to cache it.
* /
public abstract String expensiveSerialization() {...}
}
I want to stub MyClass.serialize() call in my scala test suite via Mockito:
test("some test should work as expected") {
val myClassMock = mock[MyClass]
when(myClassMock.serialize()).thenReturn("stubbedSerialization") // <--- This will not work as expected.
}
I found the stubbing will not work, as Mockito will register a method stub for MyClass.expensiveSerialization() instead of MyClass.serialize() -- however, during the actual method invocation when Mockito registering the stub, fieldToCacheSerialization will initialize with an empty String (I guess that is the smartNull response for a non-stub yet expensiveSerialization() invocation?). This will lead the stub register on MyClass.expensiveSerialization() NEVER served stub call in test!
I currently have to workaround with:
test("some test should work as expected") {
val myClassMock = mock[MyClass]
when(myClassMock.expensiveSerialization()).thenReturn("stubbedSerialization") // <-- Add this line fix the issue
when(myClassMock.serialize()).thenReturn("stubbedSerialization")
However, I kind of dislike the workaround as:
- It leaks
MyClass implementation details to my test suite -- in my test suite, MyClass.serialize() is the contact point for my test scope - I do not want to set up the stub only with having to know how MyClass.serialize() is implemented
- It is tricky that stubbing only on
myClassMock.serialize() won't work -- took me a lot of time to realize is Mockito didn't stub as expected (thought my implementation was wrong and mislead me to debug my implementations).
Wondering is there a way to tell Mockito just directly stub the method invocation that user specified instead of trying to "infer" a leaf method invocation to stub with? (e.g. do not register stub on MyClass.expensiveSerialization() when user is actually specify the stub on MyClass.serialize()).
Thanks a lot!
I have a java class (but I think java shouldn't matter, the issue should persist even given a scala implementation)
I want to stub
MyClass.serialize()call in my scala test suite via Mockito:I found the stubbing will not work, as Mockito will register a method stub for
MyClass.expensiveSerialization()instead ofMyClass.serialize()-- however, during the actual method invocation when Mockito registering the stub,fieldToCacheSerializationwill initialize with an empty String (I guess that is the smartNull response for a non-stub yetexpensiveSerialization()invocation?). This will lead the stub register onMyClass.expensiveSerialization()NEVER served stub call in test!I currently have to workaround with:
However, I kind of dislike the workaround as:
MyClassimplementation details to my test suite -- in my test suite,MyClass.serialize()is the contact point for my test scope - I do not want to set up the stub only with having to know howMyClass.serialize()is implementedmyClassMock.serialize()won't work -- took me a lot of time to realize is Mockito didn't stub as expected (thought my implementation was wrong and mislead me to debug my implementations).Wondering is there a way to tell Mockito just directly stub the method invocation that user specified instead of trying to "infer" a leaf method invocation to stub with? (e.g. do not register stub on
MyClass.expensiveSerialization()when user is actually specify the stub onMyClass.serialize()).Thanks a lot!