3

I started to use Guava Optional as a part of the null object pattern and would like to improve the use in Mockito, where null is the default return value for mocked objects. To behave correctly one needs to explicitly tell Mockito to use Optional.absent() instead:

import org.mockito.*;
import org.testng.*;
import org.testng.annotations.*;
import com.google.common.base.Optional;


public class Example {

    @Mock
    private MyObject underTest;

    @Test
    public void testExample() {
        // fails
        // assertNotNull(underTest.get());

        Mockito.when(underTest.get()).thenReturn(Optional.absent());
        Assert.assertNotNull(underTest.get());
    }

    public class MyObject {

        public Optional<Object> get() {
            return Optional.absent();
        }
    }

    @BeforeClass
    public void beforeClass() {
        MockitoAnnotations.initMocks(this);
    }
}

Is there a easy way to improve mockito to automatically return Optional.absent() instead of null if the actual type is Optional?

jan
  • 2,741
  • 4
  • 35
  • 56

3 Answers3

2

I got a first shot with the linked answer for strings.

public class OptionalAnswer extends ReturnsEmptyValues {

    @Override
    public Object answer(InvocationOnMock invocation) {
        Object answer = super.answer(invocation);
        if (answer != null) {
            return answer;
        }
        Class<?> returnType = invocation.getMethod().getReturnType();
        if (returnType == Optional.class) {
            return Optional.absent();
        }
        return null;
    }
}


@Test
public void testExample() {
    MyObject test = mock(MyObject.class, new OptionalAnswer());
    Assert.assertNotNull(test.get());
}

Won't get much easier, right?

Community
  • 1
  • 1
jan
  • 2,741
  • 4
  • 35
  • 56
  • 1
    Great solution! It can be taken a step further by making this the default behavior. Create a class called `org.mockito.configuration.MockitoConfiguration` that extends `DefaultMockitoConfiguration`. (Mockito instantiates this class via reflection). Override the `getDefaultAnswer` method to return an instance of your custom `OptionalAnswer`. Now when you create the mock using `mock(MyObject.class)` you'll get the custom answer behavior. – dnault Aug 17 '16 at 19:45
2

I tried to solve it with reflection in @Before annotated method, however, I didn't manage to get it working.

Solution you found out can be improved by creating your own static factory that creates mocks with an OptionalAnswer and use it instead of default Mockito factory:

class MockitoOptional{
    public static <T> T mock(Class<T> classToMock) {
       return Mockito.mock(classToMock, new OptionalAnswer());
    }
}

Next step will be to extend a test runner that will use this factory to inject mocks into @Mock annotated fields. Search for custom JUnit test runners if you haven't heard of them yet.

fracz
  • 20,536
  • 18
  • 103
  • 149
-1

Mockito.when(underTest.get()).thenReturn(Optional.<Object>absent());

This is all you need to do. Add the type returned from underTest.get() to your absent() call. Yes it is supposed to be on that side of the period.

Roger
  • 10,851
  • 3
  • 26
  • 39
  • I don't get the idea of that answer to copy one line from the question(!) and write this is the answer?! Have you even read the question text at all? Really thinking about a downvote here... – jan Jan 06 '17 at 07:50
  • Sorry I forgot to use code tags and `` which I had put as `` was parsed as mark up so it didn't appear in the actual answer. – Roger Jan 06 '17 at 20:22
  • I still don't get what value this unneeded more explicit code should add to my question. Of course one can add the generic type from a static method explicitly, but this is not needed if the type is obvious from content. And the idea of the question is to not need this line at all, i.e. it is _not_ an answer to extend this line with unneeded syntax sugar. – jan Jan 12 '17 at 15:12
  • Literally doesn't compile without it. – Roger Jan 12 '17 at 16:49
  • Then I would suggest to switch your compiler. Have you even really tested that or do you simply claim your incorrect statement? – jan Jan 12 '17 at 17:03