Skip to content

Default mock of Optional is not empty when using RETURN_DEEP_STUBS #2865

@big-andy-coates

Description

@big-andy-coates

Version affected: Mockito: 4.x & 5.x

If you create a mock with RETURN_DEEP_STUBS, then any method that returns a collection will, by default, return an empty collection, i.e. isEmpty returns true, etc. This is great, as it means no additional configuration of the mock is required before passing to logic that would attempt to access elements of the collection.

However, the same is not true for Optional, (and I'm assuming OptionalLong etc): if RETURN_DEEP_STUBS is used, methods that return Optional aren't treated in any special way and just return a default mock with not stubbing configured. This means isEmpty returns false, but get() returns null. This breaks the contract of Optional, causing test failures that aren't actually valid, or requiring manual configuration of the Optional mock to do-the-right-thing, cluttering test code.

Here's an example test that demonstrates this:

interface Address {
   Optional<String> getState();
}

@Test
public void shouldDefaultDeepMockOptionalsToEmpty() {
    final Address address = mock(Address.class, RETURNS_DEEP_STUBS);

    assertThat(address.getState()).isEqualTo(Optional.empty());  // <--- fails
}

@Test
public void shouldDefaultMockOptionalsToEmpty() {
    final Address address = mock(Address.class); // <-- no RETURNS_DEEP_STUBS

    assertThat(address.getState()).isEqualTo(Optional.empty());  // <--- passes
}

Note the second test, which doesn't use deep mocking, passes.

  • The mockito message in the stacktrace have useful information, but it didn't help
  • The problematic code (if that's possible) is copied here;
    Note that some configuration are impossible to mock via Mockito
  • Provide versions (mockito / jdk / os / any other relevant information)
  • Provide a Short, Self Contained, Correct (Compilable), Example of the issue
    (same as any question on stackoverflow.com)
  • Read the contributing guide

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions