Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to mock ModelMapper in Spring?

I'm trying to write unit test for my service layer:

@SpringBootTest
class ClinicServiceTest {

@Mock
private ProcedureRepository procedureRepository;
@InjectMocks
private ClinicService clinicService;

@Test
void setProcedureStatus() {
    when(procedureRepository.findById(1L)).thenReturn(Optional.of(initialEntity));
    when(procedureRepository.saveAndFlush(expectedEntity)).thenReturn(expectedEntity);
    Procedure assertProcedure = clinicService.setProcedureStatus(1L, "CANCELED");
  }
}

When i call setProcedureStatus method it throws NullPointerException because my service class uses ModelMapper that is being autowired by Spring:

@Service
@RequiredArgsConstructor
public class ClinicService {

private final ProcedureRepository procedureRepository;
private final ModelMapper modelMapper;

public Procedure setProcedureStatus(Long procedureId, String status) {
    ...
    return modelMapper.map(procedureEntity, Procedure.class);
}

}

Unit test doesn't raise Spring context, that's the reason why ModelMapper is null in Service when i call it from test. Is there ways to solve this problem?

like image 583
Alexey Avatar asked Apr 12 '20 12:04

Alexey


People also ask

What is modelmapper in Spring Boot?

ModelMapper is a Java library, which simplifies code mapping objects. Mapping can be understood as converting between two objects with similar structure. In Spring Boot there are different types of data, but the structure is almost similar, so this library can also be used with them. Example map between entity and model, entity and DTO, …

How can I mock a modelmapper class?

or you can mock ModelMapper too. Another way is to use MockitoJunitRunner and initialize your class under tests like below: Thanks to dependency injection your code is much simplier to test because you can just create your service with dependencies passed via constructor.

How do I use Mockito in a spring unit test?

But the best kind of test doesn’t use Spring at all, so let’s first look at how to use Mockito in a plain unit test to mock away unwanted dependencies. The plainest way to use Mockito is to simply instantiate a mock object using Mockito.mock () and then pass the so created mock object into the class under test:

What is the best mocking framework for Spring Boot?

As a mocking framework, we’ll use Mockito, since it’s well-rounded, well-established, and well-integrated into Spring Boot. But the best kind of test doesn’t use Spring at all, so let’s first look at how to use Mockito in a plain unit test to mock away unwanted dependencies.


2 Answers

You want to write a unit test so you shouldn't raise the spring context. Unit tests are faster than Integration tests (where often you want to raise your spring context). When it comes to unit tests you want to test unit part of your application.

It this case you are getting NPE because you didn't initialize ModelMapper.

I didn't see where you are creating your ClinicService, but there is one example how you can avoid that NPE:

@Test
void setProcedureStatus() {
    when(procedureRepository.findById(1L)).thenReturn(Optional.of(initialEntity));
    when(procedureRepository.saveAndFlush(expectedEntity)).thenReturn(expectedEntity);
    // Initialize ClinicService with mocked procedeRepository but real ModelMapper
    ClinicService clinicService = new ClinicService(procedureRepository, new ModelMapper(), ... other dependencies );
    Procedure assertProcedure = clinicService.setProcedureStatus(1L, "CANCELED");
}

or you can mock ModelMapper too.

Another way is to use MockitoJunitRunner and initialize your class under tests like below:

@RunWith(MockitoJUnitRunner.class)
 public class ExampleTest {
 
     @Mock
     private ModelMapper modelMapper;

     @Mock
     private Repository repository;

     @InjectMocks
     private ClinicService classUnderTest;
  

Thanks to dependency injection your code is much simplier to test because you can just create your service with dependencies passed via constructor.

like image 172
mtszpater Avatar answered Oct 17 '22 00:10

mtszpater


If you are testing your modelmapper map returning values, you can use @Spy. Example using:

this way is preparing a modelmapper with default constructor.

@Spy
ModelMapper modelMapper;

or you can customize with builder or constructor a modelmapper or any other types with instance creation way.

@Spy
ModelMapper modelMapper=new ModelMapper();

Therefore when you use a @InjectMocks they will inject inside the service or related field.

like image 34
withoutOne Avatar answered Oct 17 '22 00:10

withoutOne