Reputation: 41
i'm struggling with some weird problem related with Mockito and JUnit 5 with Spring Boot application.
Here is the fragment of my AccountServiceTest
class:
@ExtendWith(MockitoExtension.class)
@Import(MapperConfig.class)
class AccountServiceTest {
@Mock
private AccountRepository accountRepository;
@Mock
private ModelMapper modelMapper;
@Mock
private PasswordEncoder passwordEncoder;
@Mock
private AuthenticationManager authenticationManager;
@Mock
private JwtTokenUtil jwtTokenUtil;
@InjectMocks
private AccountService underTest;
@Test
void itShouldCreateAccountAndAddItToDatabase() {
// given
CreateAccountDto dto = new CreateAccountDto("[email protected]", "service.tester", "12345");
// when
Account account = underTest.create(dto);
Account found = accountRepository.findByUsername(account.getUsername()).orElseThrow();
// then
assertEquals(found, account);
}
...
}
Here is the service I want to test:
@Service
public class AccountService implements FieldValueExists {
@Autowired
private AccountRepository accountRepository;
@Autowired
private PasswordEncoder passwordEncoder;
@Autowired
private AuthenticationManager authenticationManager;
@Autowired
private ModelMapper modelMapper;
@Autowired
private JwtTokenUtil jwtTokenUtil;
public Account create(CreateAccountDto dto) {
Account account = modelMapper.map(dto, Account.class);
account.setHashedPassword(passwordEncoder.encode(dto.getPassword()));
accountRepository.save(account);
return account;
}
...
}
Everything seems to work in the AccountService
itself when used in the controller, but in the testing unit the modelMapper.map(...)
method returns null object, so it throws an infamous NullPointerException
.
Also I've managed to put a Configuration for this mapper in MapperConfig
:
@Configuration
public class MapperConfig {
@Bean
public ModelMapper modelMapper() {
ModelMapper modelMapper = new ModelMapper();
/*
Account's related mappings
*/
modelMapper
.typeMap(CreateAccountDto.class, Account.class);
modelMapper
.typeMap(Account.class, AccountDto.class);
modelMapper
.typeMap(Account.class, AuthorDto.class);
/*
Note's related mappings
*/
modelMapper
.typeMap(CreateNoteDto.class, Note.class);
modelMapper
.typeMap(Note.class, NoteDto.class);
modelMapper
.typeMap(EditNoteDto.class, Note.class)
.addMappings(mapper -> {
mapper.when(ctx -> ctx.getSource() != null).map(EditNoteDto::getTitle, Note::setTitle);
mapper.when(ctx -> ctx.getSource() != null).map(EditNoteDto::getContent, Note::setContent);
});
return modelMapper;
}
}
I don't know what is going wrong, since the dependencies in AccountServiceTest
are mocked correctly, I think.
Upvotes: 2
Views: 2231
Reputation: 41
Actually, it is required to mock your own implementation to every method participating in service we want to test.
For example using BDDMockito:
given(modelMapper.map(dto, Account.class))
.willReturn(/*some object we want to return*/)
It is the only thing we need in our Unit Test, because we only want to check the logic of something we're testing.
For testing every part of our service we must write Integration Test.
Yes, it was fault, and I want to thank @Turing85 for pointing me to the solution of the problem.
Upvotes: 2
Reputation: 285
Use @Autowired for ModelMapper instead of @Mock and see if the problem solves
Upvotes: 0