Home > Mobile >  Mock object cannot be cast to Entity object using ModelMapper in unit test
Mock object cannot be cast to Entity object using ModelMapper in unit test

Time:05-16

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.

CodePudding user response:

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)...

CodePudding user response:

For ModelMapper related junit test in spring-boot, perhaps you can refer to the answer on:

How to mock ModelMapper in Spring?

  • Related