I am unit testing a service method create product
. This method takes in a Dto object and then transfers the Dto object to a ProductEntity
object using ModelMapper
. This method works fine but when I unit test it, I mock the modelMapper
and stub it like this when(modelMapper.map(createProductRequestDto, ProductEntity.class)).thenReturn(expectedProduct)
with expectedProduct
is a ProductEntity
instance, it throws java.lang.ClassCastException
StackTrace:
java.lang.ClassCastException: class com.example.demo.dto.responses.product.ProductResponseDto$MockitoMock$737533970 cannot be cast to class com.example.demo.entities.ProductEntity (com.example.demo.dto.responses.product.ProductResponseDto$MockitoMock$737533970 and com.example.demo.entities.ProductEntity are in unnamed module of loader 'app')
at com.example.demo.services.implementations.product.ProductCrudServiceImpl.createProduct(ProductCrudServiceImpl.java:78)
at com.example.demo.services.product.ProductCrudServiceImplTest.createProduct_ShouldReturnProductResponseDto(ProductCrudServiceImplTest.java:136)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.base/java.lang.reflect.Method.invoke(Method.java:566)
at org.junit.platform.commons.util.ReflectionUtils.invokeMethod(ReflectionUtils.java:688)
at org.junit.jupiter.engine.execution.MethodInvocation.proceed(MethodInvocation.java:60)
at org.junit.jupiter.engine.execution.InvocationInterceptorChain$ValidatingInvocation.proceed(InvocationInterceptorChain.java:131)
at org.junit.jupiter.engine.extension.TimeoutExtension.intercept(TimeoutExtension.java:149)
at org.junit.jupiter.engine.extension.TimeoutExtension.interceptTestableMethod(TimeoutExtension.java:140)
at org.junit.jupiter.engine.extension.TimeoutExtension.interceptTestMethod(TimeoutExtension.java:84)
at org.junit.jupiter.engine.execution.ExecutableInvoker$ReflectiveInterceptorCall.lambda$ofVoidMethod$0(ExecutableInvoker.java:115)
at org.junit.jupiter.engine.execution.ExecutableInvoker.lambda$invoke$0(ExecutableInvoker.java:105)
at org.junit.jupiter.engine.execution.InvocationInterceptorChain$InterceptedInvocation.proceed(InvocationInterceptorChain.java:106)
at org.junit.jupiter.engine.execution.InvocationInterceptorChain.proceed(InvocationInterceptorChain.java:64)
at org.junit.jupiter.engine.execution.InvocationInterceptorChain.chainAndInvoke(InvocationInterceptorChain.java:45)
at org.junit.jupiter.engine.execution.InvocationInterceptorChain.invoke(InvocationInterceptorChain.java:37)
at org.junit.jupiter.engine.execution.ExecutableInvoker.invoke(ExecutableInvoker.java:104)
at org.junit.jupiter.engine.execution.ExecutableInvoker.invoke(ExecutableInvoker.java:98)
at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.lambda$invokeTestMethod$6(TestMethodTestDescriptor.java:210)
at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.invokeTestMethod(TestMethodTestDescriptor.java:206)
at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.execute(TestMethodTestDescriptor.java:131)
at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.execute(TestMethodTestDescriptor.java:65)
at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$5(NodeTestTask.java:139)
at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$7(NodeTestTask.java:129)
at org.junit.platform.engine.support.hierarchical.Node.around(Node.java:137)
at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$8(NodeTestTask.java:127)
at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:126)
at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:84)
at java.base/java.util.ArrayList.forEach(ArrayList.java:1541)
at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.invokeAll(SameThreadHierarchicalTestExecutorService.java:38)
at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$5(NodeTestTask.java:143)
at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$7(NodeTestTask.java:129)
at org.junit.platform.engine.support.hierarchical.Node.around(Node.java:137)
at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$8(NodeTestTask.java:127)
at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:126)
at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:84)
at java.base/java.util.ArrayList.forEach(ArrayList.java:1541)
at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.invokeAll(SameThreadHierarchicalTestExecutorService.java:38)
at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$5(NodeTestTask.java:143)
at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$7(NodeTestTask.java:129)
at org.junit.platform.engine.support.hierarchical.Node.around(Node.java:137)
at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$8(NodeTestTask.java:127)
at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:126)
at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:84)
at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.submit(SameThreadHierarchicalTestExecutorService.java:32)
at org.junit.platform.engine.support.hierarchical.HierarchicalTestExecutor.execute(HierarchicalTestExecutor.java:57)
at org.junit.platform.engine.support.hierarchical.HierarchicalTestEngine.execute(HierarchicalTestEngine.java:51)
at org.junit.platform.launcher.core.EngineExecutionOrchestrator.execute(EngineExecutionOrchestrator.java:108)
at org.junit.platform.launcher.core.EngineExecutionOrchestrator.execute(EngineExecutionOrchestrator.java:88)
at org.junit.platform.launcher.core.EngineExecutionOrchestrator.lambda$execute$0(EngineExecutionOrchestrator.java:54)
at org.junit.platform.launcher.core.EngineExecutionOrchestrator.withInterceptedStreams(EngineExecutionOrchestrator.java:67)
at org.junit.platform.launcher.core.EngineExecutionOrchestrator.execute(EngineExecutionOrchestrator.java:52)
at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:96)
at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:75)
at com.intellij.junit5.JUnit5IdeaTestRunner.startRunnerWithArgs(JUnit5IdeaTestRunner.java:71)
at com.intellij.rt.junit.IdeaTestRunner$Repeater$1.execute(IdeaTestRunner.java:38)
at com.intellij.rt.execution.junit.TestsRepeater.repeat(TestsRepeater.java:11)
at com.intellij.rt.junit.IdeaTestRunner$Repeater.startRunnerWithArgs(IdeaTestRunner.java:35)
at com.intellij.rt.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:235)
at com.intellij.rt.junit.JUnitStarter.main(JUnitStarter.java:54)
createProduct service method:
@Override
public ProductResponseDto createProduct(CreateProductRequestDto createProductRequestDTO) {
Long genderId = createProductRequestDTO.getGenderId();
Long sportId = createProductRequestDTO.getSportId();
List<Long> categoryIds = createProductRequestDTO.getCategoryIds();
List<Long> technologyIds = createProductRequestDTO.getTechnologyIds();
GenderEntity genderEntity = genderCrudService.findById(genderId);
SportEntity sportEntity = sportCrudService.findById(sportId);
List<CategoryEntity> categoryEntities = categoryCrudService.findByIds(categoryIds);
List<TechnologyEntity> technologyEntities = technologyService.findByIds(technologyIds);
Set<TechnologyEntity> technologyEntitySet = technologyEntities.stream().collect(Collectors.toSet());
Set<CategoryEntity> categoryEntitySet = categoryEntities.stream().collect(Collectors.toSet());
ProductEntity productEntity = modelMapper.map(createProductRequestDTO, ProductEntity.class);
productEntity.setTechnologies(technologyEntitySet);
productEntity.setCategories(categoryEntitySet);
productEntity.setGender(genderEntity);
productEntity.setSport(sportEntity);
productEntity = productRepository.save(productEntity);
AddSizeToProductRequestDto requestDto = addSizeToProductRequestDtoFactory.createAddSizeToRequestDto(productEntity.getId(), createProductRequestDTO.getProductSizeDtoList());
productEntity = productSizeService.addSizeToProduct(requestDto);
return modelMapper.map(productEntity, ProductResponseDto.class);
}
Unit test class:
public class ProductCrudServiceImplTest {
ModelMapper modelMapper;
ProductCrudServiceImpl productCrudServiceImpl;
GenderCrudService genderCrudService;
SportCrudService sportCrudService;
CategoryCrudService categoryCrudService;
ProductRepository productRepository;
TechnologyService technologyService;
ProductSizeService productSizeService;
CreateProductRequestDto createProductRequestDTO;
List<Long> categoryIds;
List<Long> technologyIds;
GenderEntity genderEntity;
SportEntity sportEntity;
List<CategoryEntity> categoryEntities;
List<TechnologyEntity> technologyEntities;
Set<TechnologyEntity> technologyEntitiesSet;
Set<CategoryEntity> categoryEntitiesSet;
List<ProductSizeDto> productSizeDtoList;
ProductEntity initProduct;
ProductEntity expectedProduct;
AddSizeToProductRequestDto addSizeToProductRequestDto;
AddSizeToProductRequestDtoFactory addSizeToProductRequestDtoFactory;
ProductResponseDto resultProductDto;
@BeforeEach
public void beforeEach() {
modelMapper = mock(ModelMapper.class);
genderCrudService = mock(GenderCrudService.class);
sportCrudService = mock(SportCrudService.class);
categoryCrudService = mock(CategoryCrudService.class);
productRepository = mock(ProductRepository.class);
technologyService = mock(TechnologyService.class);
productSizeService = mock(ProductSizeService.class);
addSizeToProductRequestDto = mock(AddSizeToProductRequestDto.class);
addSizeToProductRequestDtoFactory = mock(AddSizeToProductRequestDtoFactory.class);
productCrudServiceImpl = new ProductCrudServiceImpl(
modelMapper,
genderCrudService,
sportCrudService,
categoryCrudService,
productRepository,
technologyService,
productSizeService,
addSizeToProductRequestDtoFactory
);
createProductRequestDTO = mock(CreateProductRequestDto.class);
genderEntity = mock(GenderEntity.class);
sportEntity = mock(SportEntity.class);
categoryIds = mock(List.class);
technologyIds = mock(List.class);
categoryEntities = Arrays.asList(CategoryEntity.builder().id(1L).name("category").description("description").build());
categoryEntitiesSet = categoryEntities.stream().collect(Collectors.toSet());
technologyEntities = Arrays.asList(TechnologyEntity.builder().id(1L).name("technology").description("description").build());
technologyEntitiesSet = technologyEntities.stream().collect(Collectors.toSet());
expectedProduct = ProductEntity.builder()
.id(1L)
.name("product")
.price(1)
.year(2022)
.thumbnail("thumbnail")
.sport(sportEntity)
.gender(genderEntity)
.technologies(technologyEntitiesSet)
.categories(categoryEntitiesSet)
.description("description")
.build();
productSizeDtoList = mock(List.class);
addSizeToProductRequestDto = mock(AddSizeToProductRequestDto.class);
addSizeToProductRequestDtoFactory = mock(AddSizeToProductRequestDtoFactory.class);
resultProductDto = mock(ProductResponseDto.class);
when(createProductRequestDTO.getGenderId()).thenReturn(1L);
when(createProductRequestDTO.getSportId()).thenReturn(2L);
when(createProductRequestDTO.getCategoryIds()).thenReturn(categoryIds);
when(createProductRequestDTO.getTechnologyIds()).thenReturn(technologyIds);
when(genderCrudService.findById(1L)).thenReturn(genderEntity);
when(sportCrudService.findById(1L)).thenReturn(sportEntity);
when(categoryCrudService.findByIds(categoryIds)).thenReturn(categoryEntities);
when(technologyService.findByIds(technologyIds)).thenReturn(technologyEntities);
when(modelMapper.map(createProductRequestDTO, ProductEntity.class)).thenReturn(expectedProduct);
when(productRepository.save(any())).thenReturn(expectedProduct);
when(createProductRequestDTO.getProductSizeDtoList()).thenReturn(productSizeDtoList);
when(addSizeToProductRequestDtoFactory.createAddSizeToRequestDto(1L, productSizeDtoList)).thenReturn(addSizeToProductRequestDto);
when(productSizeService.addSizeToProduct(addSizeToProductRequestDto)).thenReturn(expectedProduct);
when(modelMapper.map(any(), ArgumentMatchers.<Class<ProductResponseDto>>any())).thenReturn(resultProductDto);
}
@Test
public void createProduct_ShouldReturnProductResponseDto() {
ProductResponseDto result = productCrudServiceImpl.createProduct(createProductRequestDTO);
ArgumentCaptor<ProductEntity> productCaptor = ArgumentCaptor.forClass(ProductEntity.class);
verify(productRepository).save(productCaptor.capture());
ProductEntity savedProduct = productCaptor.getValue();
verify(modelMapper).map(productCaptor.capture(), ProductEntity.class);
ProductEntity mappedProduct = productCaptor.getValue();
//
assertEquals(savedProduct, expectedProduct);
assertEquals(mappedProduct, expectedProduct);
assertThat(result, is(resultProductDto));
}
I did some research on this but I can't identify the root cause and I have no idea how this could happen. Could you please help me with this?
Thank you very much for your precious time.
The last mock in your beforeEach
method when(modelMapper.map(any(), ArgumentMatchers.<Class<ProductResponseDto>>any())).thenReturn(resultProductDto);
seems to be causing the issue.
As the stack trace shows, the returned object from the mocked stub is of type class com.example.demo.dto.responses.product.ProductResponseDto$MockitoMock$737533970
.
You can verify it is the same object as the one created at resultProductDto = mock(ProductResponseDto.class);
by checking the hashcodes.
As a fix, in order to mock the behaviour of modelMapper.map(productEntity, ProductResponseDto.class);
, you should try using when(modelMapper.map(any(ProductEntity.class)...