- 
                Notifications
    You must be signed in to change notification settings 
- Fork 60
Description
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 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 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!