0

When stubbing with Mockito, we ofen specify a concrete argument for a method. After that, we can call the stubbed method with the same argument. For example, in the following code, the get() is stubbed with an argument of 0. So, when calling get(), the argument of get() is also 0. As such, the get() will return a integer, that is 3.

@RunWith(MockitoJUnitRunner.class)
public class MockitoTest {
    @Mock
    private List<Integer> mockedList;

    @Test
    public void test() {
        when(mockedList.get(0)).thenReturn(3);
        int element = mockedList.get(0);
        assertEquals(3, element);
    }
}

If the calling statement is modified as such:

int element = mockedList.get(1);

That is the argument is changed to 1, then Mockito throw 'NullPointerException', rather than a 'AssertionError'。 where is the null pointer?

And if we consider a case of throwing an exception rather than returning a value, the situation is more interesting. As the following code shows, though the two arguments of get() are different, a 'AssertionError' is thrown rather than a 'NullPointerException'.

@Test(expected = IndexOutOfBoundsException.class)
public void test() {
    when(mockedList.get(0)).thenThrow(new IndexOutOfBoundsException());
    mockedList.get(1);
}

It seems that when arguments are different, Mockito has different behaviors.

xflotus
  • 11
  • 2
  • It better to use @Spy with list – petrov.aleksandr Apr 07 '21 at 13:42
  • 1
    `mockedList.get(1)` returns `null`. Now auto-boxing `null` to an `int` will fail with a `NullPointerException`. – M. Deinum Apr 07 '21 at 13:53
  • This is also why your second sample succeeds as there is no auto-unboxing there is no `NullPointerException` and thus a simple assertion error is thrown (as it was expecting an error but nothing actually happened). – M. Deinum Apr 07 '21 at 14:03

3 Answers3

4

When doing mockedList.get(1) and you haven't registered behaviour for that it will return a default value. Mockito will by default return null.

Your list contains Integer elements not int elements (a primive collection isn't (yet) available in plain Java).

Now due to your int element = mockedLIst.get(1) it will try to auto-unbox from an Integer to int. However, due to that being null, it will fail with a NullPointerException. As it will try to call intValue() on the given Integer or in this case null.

See also Unboxing Null-Object to primitive type results in NullPointerException, fine?

To solve, using Integer instead of int would remove the auto-unboxing and make it work as intended.

@Test
public void testNoValue() {
    when(mockedList.get(0)).thenReturn(3);
    Integer element = mockedList.get(1);
    assertEquals(3, element);
}
M. Deinum
  • 115,695
  • 22
  • 220
  • 224
1
when(mockedList.get(0)).thenReturn(3);

This line is mocking only getting 0 element so whenever you try to get different one you will get error. You need to pass argument like "any" or anyInt so you can test get(0), get(1) etc.

Mocking is like defining behavior for specific methods. In your example you are mocking method get for list with static parameter which is 0. It means that there are no defined behavior for other params like "1" that's why you receive that error.

EDIT:

Whenever you try go get element which is not mocked you will get null instead. So mockedList.get(1) will return null. When you try to assing that null to primitive int it will throw NullPointerException

Rafał Sokalski
  • 1,817
  • 2
  • 17
  • 29
0

Your test with .get(1):

@Test
public void test() {
    when(mockedList.get(0)).thenReturn(3);
    int element = mockedList.get(1);
    assertEquals(3, element);
}

Will throw NullPointerException on line int element = mockedList.get(1); because mockedList is mocked instance and does not know what to return in the case of parameter 1.

In the case of assertEquals(3, element); where the element is null you will have AssertionError.

Akif Hadziabdic
  • 2,692
  • 1
  • 14
  • 25