Home > Back-end >  Test fails on a null pointer exception when I use @InjectMocks
Test fails on a null pointer exception when I use @InjectMocks

Time:08-24

I am practising restful api endpoints using https://api.predic8.de/shop/docs

Here is my repo

I am getting a NPE failure when I try to use @InjectMocks during my TDD approach

However, I can make my test pass when I make a direct call in the setup()

vendorService = new VendorServiceImpl(VendorMapper.INSTANCE, vendorRepository);

I wanted to extend my learning by trying to create an endpoint for getting all vendors.

When I employ TDD along the way, but, my test getAllVendors() fails on a NPE when I try to use @InjectMocks but passes when I substitute it for a direct call in the setup() method.

The NPE is linked to the mapper class I think.

Here are the classes that I believe are useful. VendorServiceTest, VendorServiceImpl, VendorMapper.

I have commented out the direct call in the setup as I want to get the test passing using @InjectMocks

package guru.springfamework.services;

import guru.springfamework.api.v1.mapper.VendorMapper; import guru.springfamework.api.v1.model.VendorDTO; import guru.springfamework.domain.Vendor; import guru.springfamework.repositories.VendorRepository; import org.junit.Before; import org.junit.Test; import org.mockito.InjectMocks; import org.mockito.Mock; import org.mockito.MockitoAnnotations; import org.springframework.test.web.servlet.MockMvc;

import java.util.Arrays; import java.util.List;

import static org.junit.Assert.*; import static org.mockito.Mockito.when;

public class VendorServiceTest {

public static final String NAME = "Tasty";
public static final Long ID = 1L;

@Mock
VendorMapper vendorMapper;

@Mock
VendorRepository vendorRepository;

@InjectMocks
VendorServiceImpl vendorService;

//VendorService vendorService;

@Before
public void setUp() throws Exception {
    MockitoAnnotations.initMocks(this);
    //vendorService = new VendorServiceImpl(VendorMapper.INSTANCE, vendorRepository);
}

@Test
public void getAllVendors() {
    //given
    List<Vendor> vendors = Arrays.asList(new Vendor(), new Vendor(), new Vendor());

    when(vendorRepository.findAll()).thenReturn(vendors);

    //when
    List<VendorDTO> vendorDTOList = vendorService.getAllVendors();

    //then
    assertEquals(3, vendorDTOList.size());
}

@Test
public void findByName() {
}

}

package guru.springfamework.services;

import guru.springfamework.api.v1.mapper.VendorMapper; import guru.springfamework.api.v1.model.VendorDTO; import guru.springfamework.repositories.VendorRepository; import org.springframework.stereotype.Service;

import java.util.List; import java.util.stream.Collectors;

@Service public class VendorServiceImpl implements VendorService {

private final VendorMapper vendorMapper;
private final VendorRepository vendorRepository;

public VendorServiceImpl(VendorMapper vendorMapper, VendorRepository vendorRepository) {
    this.vendorMapper = vendorMapper;
    this.vendorRepository = vendorRepository;
}

@Override
public List<VendorDTO> getAllVendors() {
    return vendorRepository
            .findAll()
            .stream()
            .map(vendor -> {
                VendorDTO vendorDTO = vendorMapper.vendorToVendorDTO(vendor);
                vendorDTO.setVendorUrl("/api/v1/vendors/"   vendor.getId());
                return vendorDTO;
            })
            .collect(Collectors.toList());
}

@Override
public VendorDTO findByName(String name) {
    return vendorMapper.vendorToVendorDTO(vendorRepository.findByName(name));
}

@Override
public VendorDTO getVendorById(Long id) {
    return vendorMapper.vendorToVendorDTO(vendorRepository.findById(id).orElseThrow(RuntimeException::new));
}

}

package guru.springfamework.api.v1.mapper;

import guru.springfamework.api.v1.model.VendorDTO; import guru.springfamework.domain.Vendor; import org.mapstruct.Mapper; import org.mapstruct.factory.Mappers;

@Mapper public interface VendorMapper {

VendorMapper INSTANCE = Mappers.getMapper(VendorMapper.class);

VendorDTO vendorToVendorDTO(Vendor vendor);

}

Does anyone know where and why I am going wrong?

CodePudding user response:

The problem is that you created mock object for the mapper, but you didn't say what should happen when the method vendorToVendorDTO is called. Therefore, when that method is called in the next line of code:

VendorDTO vendorDTO = vendorMapper.vendorToVendorDTO(vendor);

It will return null, and then in this line of code:

vendorDTO.setVendorUrl("/api/v1/vendors/"   vendor.getId());

You will get NullPointerException.

To make this work, change your getAllVendors() method as follows:

  @Test
    public void getAllVendors() {
        //given
        List<Vendor> vendors = Arrays.asList(new Vendor(), new Vendor(), new Vendor());
        VendorDTO mockDto = mock(VendorDTO.class);
        when(vendorRepository.findAll()).thenReturn(vendors);
        when(vendorMapper.vendorToVendorDTO(any(Vendor.class))).thenReturn(mockDto);
        //when
        List<VendorDTO> vendorDTOList = vendorService.getAllVendors();

        //then
        assertEquals(3, vendorDTOList.size());
    }

And the test should pass.

CodePudding user response:

Have you tried to put @RunWith(MockitoJUnitRunner.class)/@ExtendsWith(MockitoExtension.class) over your test class?

  • Related