Mockito RETURNS_SMART_NULLS answer weird behavior

4.5k views Asked by At

I'm using the annotation @Mock(answer=Answers.RETURNS_SMART_NULL) with Mockito 1.9.5 in order to get some SmartNullPointerException when some unexpected mock calls occurs.

Unfortunately, the test pass, even without mocking at least one important call. To be clear : My point is not to find by myself what I'm missing but to fail the test because I didn't mock the methods. I would want to do it without using Mockito.verifyNoMoreInteractions(...)

My test :

@RunWith(MockitoJUnitRunner.class)
public class ContextServiceImplTest {

    @Mock(answer = Answers.RETURNS_SMART_NULLS)
    private IAccountDAO accountDaoMock; 
    @Mock(answer = Answers.RETURNS_SMART_NULLS)
    private IRuleService ruleServiceMock;
    @Mock(answer = Answers.RETURNS_SMART_NULLS)
    private ISensorDAO sensorDAOMock;

    private ContextServiceImpl contextService;

    @Before
    public void before() {
        contextService = new ContextServiceImpl(accountDaoMock, ruleServiceMock, sensorDAOMock);
    }

    @Test
    public void fillSensor() throws Exception {
        // given
        String givenSensorId = "123"
        final EventDTO givenEvent = new EventDTO();
        givenEvent.setSensorId(givenSensorId)

        // when
        final Context context = contextService.getContext(givenEvent);

        // then (should fail and throw explicit exception

    }

The code to be tested :

public class ContextServiceImpl {
    ...

    public Context getContext(final EventDTO event) throws Exception {
        final String sMethodName = "getContext";
        final String sensorId = event.getSensorId();
        Context context = new Context();

        try {
            final Sensor sensor = sensorDAO.findById(sensorId);
            context.setSensor(sensor);
            return context;
        } catch (final NoResultException nre) {
            throw new BusinessException(ValidationCode.UNSUPPORTED_VALUE, "sensorId");
        } catch (final PersistenceException pe) {
            throw new TechnicalException(TechnicalCode.DATABASE_ACCESS_PROBLEM);
    }
}

Thanks for your comments / advices / explainations.

2

There are 2 answers

6
Blake Yarbrough On BEST ANSWER

You need to call a method on the null object sensor for the test to fail.

It seems like you are never using the null object sensor. This means you won't get any NullPointerExceptions (smart or not)

you could do an

AssertEquals(context.getSensor().someMethod(), expectedResult);

or just a

context.getSensor().someMethod();

to get an exception. But

AssertNotNull(context.getSensor());

won't be sufficient to get the SmartNullPointerException

0
Makoto On

Your tests will still pass because you're not invoking anything with the result of any of those mocked calls.

RETURNS_SMART_NULLS only throws a SmartNullPointerException if you attempt to dereference something that is a SmartNull. In essence, it's telling you that you're dereferencing a null value in a friendlier way, and you're not doing that with your current code.

First - you new up a Context. Unless you're getting into the weeds of threading problems, that will never come back null.

Next - you're passing in a newed EventDTO. For the same reasons above, that won't be null either.

The result of sensor may be null, but it doesn't matter - you're merely passing it through to the context without invoking any logic on it.

I'm not convinced that RETURNS_SMART_NULLS is going to work the best for your scenario. I'd recommend that you remove those answers from the mock objects. This will cause your test to fail because you haven't expected any of those interactions.