Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

Mockito won't stub method as expected if the method implemented with Singleton pattern. #461

Copy link
Copy link
@CharlesZ-Chen

Description

@CharlesZ-Chen
Issue body actions

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:

  1. 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
  2. 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!

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions

      Morty Proxy This is a proxified and sanitized view of the page, visit original site.