2

I'm using Android SDK and junit4 + Mockito for unit testing. Say I have a class like this in my app:

public class Container{

  @NonNull private Set<String> values = new HashSet<>();

  public void addValue(String value) {
    values.add(value);
  }

  @NonNull
  public Set<String> getValues() {
    return values;
  }
}

And I also have a unit test with Mockito that looks like this:

public class ContainerTest {

  private Container container;

  @Before
  public void before() {
    container = mock(Container.class);
  }

  @Test
  public void shouldAddValue() {
    container.add("test_value");
    assertTrue(container.getValues.contains("test_value"));
  }

}

This test actually fails on line "container.add("test_value");" because mock(Container.class) creates a class in which values field is actually set to null, so values.add(value) in addValue() method throws an NPE. I could add a null check in addValue() to fix this, but that seems absurd, since values are already declared non null.

Is there any way to make Mockito respect @NonNull annotations and initialize the field properly?

Anton Cherkashyn
  • 5,719
  • 6
  • 43
  • 80

1 Answers1

2

I think you aren't using Mockito in the right way, since you have to define the Mockito behaviors.

For instance, you should have something like this:

@Test
public void shouldAddValue() {
    Set<String> mySet = new HashSet<String>();
    mySet.put("test_value");

    // Mock container getValues() method to return mySet
    when(container.getValues()).thenReturn(mySet); // do import static for Mockito.when

    assertTrue(container.getValues().contains("test_value"));
}

Mockito works pretty well when you mock responses, but what you want is to let Mockito to initialize classes for you which clearly it isn't Mockito goals.

Therefore, if you want to test your Container object, then you don't have to mock Container itself and you can have something like this:

public class ContainerTest {

    private Container container;

    @Before
    public void before() {
        container = new Container(); // Initialize container
    }

    @Test
    public void shouldAddValue() {
        container.addValue("test_value");
        assertTrue(container.getValues().contains("test_value"));
    }

}
Federico Piazza
  • 30,085
  • 15
  • 87
  • 123
  • Hey, thanks. I went with the first option, mocking getValues() method. – Anton Cherkashyn Nov 11 '15 at 04:45
  • @AntonCherkashyn glad to help. Thanks for the tick – Federico Piazza Nov 11 '15 at 14:50
  • You're not supposed to mock() the class under test, that's not how testing works. Mock the class's dependencies necessary to stimulate the required behaviour under test. In this scenario, there is no reason to mock anything at all. – gary Oct 28 '19 at 12:51