TenDan
TenDan

Reputation: 41

map() method from mocked ModelMapper returns null value

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

Answers (2)

TenDan
TenDan

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

Azadi Yazdani
Azadi Yazdani

Reputation: 285

Use @Autowired for ModelMapper instead of @Mock and see if the problem solves

Upvotes: 0

Related Questions