I have:
Java Spring WEB app. Unit-testing MapStruct with JPA repository injected (JUnit, Mockito).
My problem:
I made my tests work, but I can’t understand how they work and I have doubts whether it is a good practice in unit-testing.
Long detailed story:
I am writing unit-tests for the MapStruct class (ExchangeRateMapper
, or rather ExchangeRateMapperImpl
).
This mapper has injected dependency – JPA repository (CurrencyRepository
).
This is simplified view of mapper:
@Mapper(componentModel = "spring")
public abstract class ExchangeRateMapper {
@Autowired
private CurrencyRepository currencyRepository;
// ...
}
I tried to write tests, mocking JPA repository.
That way it doesn’t work:
@ExtendWith(SpringExtension.class)
@ExtendWith(MockitoExtension.class)
@SpringBootTest(classes = {ExchangeRateMapperImpl.class})
public class ExchangeRateMapperTests {
@Mock
CurrencyRepository currencyRepository;
@InjectMocks
@Autowired
ExchangeRateMapper exchangeRateMapper;
// ...
@Test
void exchangeRateXMLOToExchangeRateDOTest() {
Mockito.when(currencyRepository.findByCode("EUR")).thenReturn(Optional.ofNullable(currencyEUR));
Mockito.when(currencyRepository.findByCode("USD")).thenReturn(Optional.ofNullable(currencyUSD));
ExchangeRateDO result = exchangeRateMapper.exchangeRateXMLOToExchangeRateDO(exchangeRateXMLO);
Assertions.assertEquals(exchangeRateDO, result);
}
}
However, when I changed @Mock
to @MockBean
(org.mockito.Mock
to org.springframework.boot.test.mock.mockito.MockBean
)
and @InjectMocks
to @Inject
(org.mockito.InjectMocks
to jakarta.inject.Inject
),
then it works:
@ExtendWith(SpringExtension.class)
@ExtendWith(MockitoExtension.class)
@SpringBootTest(classes = {ExchangeRateMapperImpl.class})
public class ExchangeRateMapperTests {
@MockBean
CurrencyRepository currencyRepository;
@Inject
@Autowired
ExchangeRateMapper exchangeRateMapper;
// ...
@Test
void exchangeRateXMLOToExchangeRateDOTest() {
Mockito.when(currencyRepository.findByCode("EUR")).thenReturn(Optional.ofNullable(currencyEUR));
Mockito.when(currencyRepository.findByCode("USD")).thenReturn(Optional.ofNullable(currencyUSD));
ExchangeRateDO result = exchangeRateMapper.exchangeRateXMLOToExchangeRateDO(exchangeRateXMLO);
Assertions.assertEquals(exchangeRateDO, result);
}
}
Can somebody explain, please, why it works only that strange way?
Is this approach acceptable or, if not, what would be better solution to test such mapper?
I expected tests to work with @Mock
and @InjectMocks
. I guess that problem is in ExchangeRateMapper
being abstract class and CurrencyRepository
being interface, withal me wanting dependencies be injected automatically within Spring context. Still, I don’t get where exactly is problem.
V. Gluhih is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.