I'm having a NPE using ModelMapper
CatalogServiceTest
@RunWith(SpringJUnit4ClassRunner.class)
@SpringBootTest
public class CatalogServiceTest {
@Rule
public ExpectedException thrown = ExpectedException.none();
@InjectMocks private CatalogService service;
@Mock ModelMapper modelMapper;
@Mock CatalogMapper catalogMapper;
@Mock CatalogRepository catalogRepository;
@Before
public void setUp() throws Exception {
// MockitoAnnotations.initMocks(this);
CatalogEntity catalogEntity = new CatalogEntity();
catalogEntity.setId("id");
catalogEntity.setCode("code");
catalogEntity.setType("type");
catalogEntity.setValue("value");
// Optional<CatalogEntity> optionalCatalog = Optional.of(catalogEntity);
when(catalogRepository.findByCode(any(String.class))).thenReturn(catalogEntity);
}
@Test
public void whenFindByCode() {
//Act
CatalogDto myCatalogDto = service.findByCode("code");
//Assert
assertTrue(myCatalogDto.getCode().equals("code"));
}
}
CatalogService
@Service
public class CatalogService {
private static final Logger LOGGER = LoggerFactory.getLogger(CatalogService.class);
@Autowired
CatalogRepository catalogRepository;
@Autowired
CatalogMapper catalogMapper;
/**
*
* @param type
* @return catalog objects which type is type
*/
public List<CatalogDto> findByType(String type) {
LOGGER.info("Getting catalogs by type {}", type);
List<CatalogEntity> catalogsEntityList = catalogRepository.findByType(type);
List<CatalogDto> catalogDtoList = new ArrayList<>();
catalogsEntityList.forEach(catalogEntity -> {
catalogDtoList.add(catalogMapper.convertCatalogEntityToCatalogDto(catalogEntity));
});
return catalogDtoList;
}
/**
* Find catalog by code.
* @param code
* @return catalog
*/
public CatalogDto findByCode(String code) {
LOGGER.info("Getting catalogs by code {}", code);
return catalogMapper.convertCatalogEntityToCatalogDto(catalogRepository.findByCode(code));
}
}
CatalogMapper
@Component
public class CatalogMapper {
@Autowired
private ModelMapper modelMapper;
/**
* Converts CatalogEntity object to CatalogDto object
* @param catalogEntity
* @return converted CatalogDto object
*/
public CatalogDto convertCatalogEntityToCatalogDto(CatalogEntity catalogEntity) {
return modelMapper.map(catalogEntity, CatalogDto.class);
}
}
CatalogRepository
@Repository
public interface CatalogRepository extends MongoRepository<CatalogEntity, String> {
List<CatalogEntity> findByType(String type);
CatalogEntity findByCode(String code);
}
The problem
The catalogRepository.findByCode(code)
is returning a CatalogEntity object as expected and the problem comes after executing catalogMapper.convertCatalogEntityToCatalogDto(catalogRepository.findByCode(code));
that return null.
I'm using Intellij and this is the breakpoint just right before execute catalogMapper.convertCatalogEntityToCatalogDto
function.
The catalogMapper is a mock with no stubbed methods.
There are a few ways in which you can fix your test:
Option 1: only test interaction with CatalogMapper
In this option, you stub a call to
catalogMapper.convertCatalogEntityToCatalogDto
. This is a thin unit test, you only test interactions with collaborating services.As you said you want to test real implementation of mapper, there are two options:
Option 2: use SpringBootTest
In this option, you rely on SpringBootTest to set up your entire application context.
You need following changes:
@Autowired
instead of@InjectMock
to get you object under test@MockBean
instead of@Mock
for repository.SpringBootTest
ignores@Mock
.@SpringBootTest
in your code)Option 3: construct services you need yourself
@SpringBootTest
This approach creates only objects that are used by your test, not entire application context, so will likely result in leaner test that option 2.