Search code examples
javaspring-bootmockitospring-testmodelmapper

Spring Test Mapper Return Null


I am writing test unit for my backend project. Also I am using ModelMapper for map functions. But when I write getAll() or update() etc. at test method from manager ProductManager, Spring says

org.modelmapper.ModelMapper.map(Object, java.lang.Class)" because the return value of "hakan.productData.core.utilities.mappers.ModelMapperService.forRequest()" is null

I didn't figure it out. Can you help me please?

ProductManager =

@Service
@AllArgsConstructor
@Transactional
public class ProductManager implements ProductService {

    private ProductRepository productRepository;
    private ProductBusinessRules productBusinessRules;
    private ModelMapperService modelMapperService;


    @Override
    @Transactional(readOnly = true)
    public List<GetAllProductsResponse> getAll() {
        List<Product> products = productRepository.findAll();
        List<GetAllProductsResponse> productsResponse= products.stream()
                .map(product -> this.modelMapperService.forResponse().map(product, GetAllProductsResponse.class)).collect(Collectors.toList());
        return productsResponse;
    }

    @Override
    public void add(CreateProductRequest createProductRequest) {
        this.productBusinessRules.checkIfProductNameExists(createProductRequest.getName());
        Product product = this.modelMapperService.forRequest().map(createProductRequest,Product.class);
        this.productRepository.save(product);
    }

    @Override
    public UpdateProductRequest update(UpdateProductRequest updateProductRequest) {
        Product product = this.modelMapperService.forRequest().map(updateProductRequest,Product.class);
        this.productRepository.save(product);
        return updateProductRequest;
    }

ModelMapperManager =

@Service
@AllArgsConstructor
public class ModelMapperManager implements ModelMapperService {
    private ModelMapper modelMapper;
    @Override
    public ModelMapper forResponse() {
        this.modelMapper.getConfiguration()
                .setAmbiguityIgnored(true)
                .setMatchingStrategy(MatchingStrategies.LOOSE);
        return this.modelMapper;
    }

    @Override
    public ModelMapper forRequest() {
        this.modelMapper.getConfiguration()
                .setAmbiguityIgnored(true)
                .setMatchingStrategy(MatchingStrategies.STANDARD);
        return this.modelMapper;
    }
}

ProductManagerTest =

@ExtendWith(MockitoExtension.class)
public class ProductManagerTest {


    @Mock
    private ProductRepository productRepository;
    @Mock
    private ProductBusinessRules productBusinessRules;
    @Mock
    private ModelMapperService modelMapperService;
    @Mock
    private ModelMapperManager modelMapper;

    @InjectMocks
    private ProductManager productManager;

    @Test
    @DisplayName("Should Find Post By Id")
    void shouldFindPostById() {
        Product product = new Product(123,"Milk","Drink",10,true,5);
        GetAllProductsResponse expectedProductResponse = new GetAllProductsResponse(123,"Milk","Drink",10,true,5);
        Mockito.when(productRepository.findById(123)).thenReturn(Optional.of(product));

        Optional<Product> actualPostResponse = productManager.getById(123);

        assertThat(actualPostResponse.get().getId()).isEqualTo(expectedProductResponse.getId());
        assertThat(actualPostResponse.get().getName()).isEqualTo(expectedProductResponse.getName());
        System.out.println("Test was successful");
    }

       @Test
       @DisplayName("Should Update By If")
       void shouldUpdateById(){

           Product product = Product.builder()
                   .name("Milk")
                   .category("Drink")
                   .price(10)
                   .quantity(10)
                   .onOffer(true)
                   .build();

           UpdateProductRequest getAllProductsResponse = UpdateProductRequest.builder()
                   .id(1)
                   .name("Coke")
                   .category("Drink")
                   .price(5)
                   .quantity(10)
                   .onOffer(true)
                   .build();
           when(productRepository.save(Mockito.any(Product.class))).thenReturn(product);
           when(productRepository.findById(0)).thenReturn(Optional.ofNullable(product));
           UpdateProductRequest updatedProduct = productManager.update(getAllProductsResponse);
           assertThat(updatedProduct).isNotNull();


       }

}

shouldFindPostById test method works fine because I did not use any mapper methods but the other doesn't work.


Solution

  • I think your problem is that you try to mock interface ModelMapperService in your test class, but you do not mock class ModelMapperManager. It means that when you call method modelMapperService.forRequest(), it returns null value.

    Updated code:

    @ExtendWith(MockitoExtension.class)
    public class ProductManagerTest {
    
        @Mock
        private ProductRepository productRepository;
        
        @Mock
        private ProductBusinessRules productBusinessRules;
    
        @Mock
        private ModelMapperManager modelMapperManager;
    
        @Mock
        private ModelMapper modelMapper;
    
        @InjectMocks
        private ProductManager productManager;
    
        @Test
        @DisplayName("Should Update By If")
        void shouldUpdateById() {
            Product product = Product.builder()
                    .name("Milk")
                    .category("Drink")
                    .price(10)
                    .quantity(10)
                    .onOffer(true)
                    .build();
    
            UpdateProductRequest updateProductRequest = UpdateProductRequest.builder()
                    .id(1)
                    .name("Coke")
                    .category("Drink")
                    .price(5)
                    .quantity(10)
                    .onOffer(true).build();
    
            when(modelMapperManager.forRequest()).thenReturn(modelMapper);
            when(productRepository.save(Mockito.any(Product.class))).thenReturn(product);
            when(productRepository.findById(0)).thenReturn(Optional.ofNullable(product));
    
            UpdateProductRequest updatedProduct = productManager.update(updateProductRequest);
    
            assertThat(updatedProduct).isNotNull();
        }
    }