TijnvdEijnde
TijnvdEijnde

Reputation: 191

Mockito + JUnit test returns a NullPointerException

I am trying to Mock classes but i keep getting a NPE. I've seen this post Mockito - NullpointerException when stubbing Method. In this post they explain this:

"The default return value of methods you haven't stubbed yet is false for boolean methods, an empty collection or map for methods returning collections or maps and null otherwise. This also applies to method calls within when(...)."

I am almost certain that this applies to my problem as well. But i can not find a solution for it. I've been trying for almost 10 hours right now.

Also i read something about @Autowired and @Before, apparently @autowired is created before @before, this could also explain my NPE.

The NPE is thrown at the @Test void getPlantSpeciesById, because foundPlantSpecies is null and so is plantSpeciesServiceMock.getPlanySpeciesById(1). It feels like @Before is not run at all.

Excuse me, if i am missing something, i am really tired at the moment but i am desperately searching for a solution.

Here is my Code:

@SpringBootTest(classes = PlantSpeciesService.class)
@Import({TestConfig.class})
@RunWith(MockitoJUnitRunner.class)
@TestInstance(TestInstance.Lifecycle.PER_CLASS)
class PlantSpeciesServiceTest {

@MockBean
private PlantSpeciesRepository plantSpeciesRepository;

@MockBean
private ModelMapper modelMapper;

@Autowired
private PlantSpeciesService plantSpeciesServiceMock;

@Before("com.oopa.domain.services.PlantSpeciesService")
public void setup() {
    MockitoAnnotations.initMocks(this);
    PlantSpecies tulip = new PlantSpecies();
    tulip.setId(1);
    tulip.setMinHumidity(200);
    tulip.setMaxHumidity(400);
    tulip.setName("Tulip");



    Mockito.when(plantSpeciesRepository.findById(tulip.getId())).thenReturn(
            Optional.of(this.modelMapper.map(tulip, com.oopa.dataAccess.model.PlantSpecies.class))
    );
}

@Test
void getPlantSpeciesById() {
    PlantSpecies foundPlantSpecies = plantSpeciesServiceMock.getPlantSpeciesById(1);

    System.out.println(plantSpeciesServiceMock.getPlantSpeciesById(1));
    System.out.println(foundPlantSpecies);
    System.out.println();
    assertEquals("Tulip", foundPlantSpecies.getName());
}

}

Upvotes: 0

Views: 2130

Answers (2)

Mike3355
Mike3355

Reputation: 12081

Do not mock what is being tested. Just the dependencies.

class PlantSpeciesServiceTest {

@Mock
private PlantSpeciesRepository mockedPlantSpeciesRepository;

@Mock
private ModelMapper modelMapper;

private PlantSpeciesService underTest;


public void setup() {
    init(this);
    underTest = new PlantSpeciesService(mockedPlantSpeciesRepository);

  /*You might need this (sometimes you will)*/
  //mockedPlantSpeciesRepository = mock(PlantSpeciesRepository.class);

}

Then

  PlantSpecies tulip = new PlantSpecies();
    tulip.setId(1);
    tulip.setMinHumidity(200);
    tulip.setMaxHumidity(400);
    tulip.setName("Tulip");

when(underTest.foo).thenReturn(tulip);

Now

Tulip result = underTest.foo;

assertEquals(result, tulip);

Something like this should get the job done. Happy coding.

Upvotes: 0

Mark Bramnik
Mark Bramnik

Reputation: 42461

First things first @SpringBootTest is used for integration testing, while MockitoJunitRunner is for unit testing - and you should never mix them. The difference is crucial...

It looks like you're trying to do unit testing here, so please try to remove @SpringBootTest and other annotations - basically everything but mockito runner.

After this step, the test wont try to start the spring context and will technically become a unit test

Now, after this step, change @MockBean to @Mock. Using @MockBean makes sense only if your test runs with spring while @Mock is the annotation honored by the mockito runner

After this step you should stop and understand what exactly would you like to test - what is the unit here? A service? It looks like that but then - you should create an instance of the service with new and call the real method, in the question you're trying to call the method on mock, which does not sound right logically....

Bottom line I suggest to start off with proper understanding of how to write unit tests (with or without mockito) and only after that delve into the complicated but powerful integration testing framework of spring boot here. Sorry if the answer seems unclear but I feel like there are too many things in the code in the question that look wrong so the question IMO cant be answered with one or two lines of code.

Upvotes: 1

Related Questions