Mockito throwing a NullPointer Exception testing Service Layer - spring-boot

I'm trying to learn mockito by testing a service layer, but
CarServiceTest.java
#RunWith(MockitoJUnitRunner.class)
#ContextConfiguration(classes = {CarService.class})
public class CarServiceTest {
#InjectMocks
private CarService carService;
#Mock
private CarRepository carRepository;
#Test
public void getCarDetails_returnsCarInfo() {
//Mockito.when **** is not able to mock, not sure why.
Mockito.when(this.carRepository.findByName("prius")).thenReturn(new Car("prius","hybrid"));
Car expected = new Car("prius", "hybrid");
//Car expected = carService.getCarDetails("prius");
Assertions.assertThat(expected.getName()).isEqualTo("prius");
Assertions.assertThat(expected.getType()).isEqualTo("hybrid");
}
CarService.java
#Service
public class CarService {
#Autowired
CarRepository carRepository;
public Car getCarDetails(String name) {
Car car = carRepository.findByName(name);
if (car == null) {
throw new CarNotFoundException();
}
System.out.println(car.getName());
return car;
}
CarRepository.java
#Repository
public class CarRepository {
public Car findByName(String name) {
if (name.equals("prius")){
Car car = new Car("prius", "hybrid");
return car;
} else {
throw new CarNotFoundException();
}
}

#InjectMocks won't inject into #Autowired fields. Change CarService to constructor injection.

Turned out was importing org.junit.jupiter.api.Test, I changed to org.junit.Test and it worked fine.

Related

Why i get null insted of mock?

I have a project with follwing classes:
#Repository
public interface SensorRepository extends JpaRepository<Sensor, Long> {
}
#Service
#RequiredArgsConstructor
public class SensorsServiceImpl implements SensorService {
private final SensorRepository sensorRepository;
#Override
#Transactional
public Sensor save(Sensor sensor) {
return sensorRepository.save(sensor);
}
...
}
I created test to try Mockito
#RunWith(MockitoJUnitRunner.class)
class SensorsServiceImplTest {
#Mock
private SensorRepository sensorRepository;
#InjectMocks
private SensorService sensorService;
#Test
public void wasSensorSaved(){
Sensor sensor = Sensor.builder().id(1L).build();
when(sensorRepository.save(sensor)).thenReturn(sensor);
Sensor savedSensor = sensorService.save(sensor);
assertThat(savedSensor).isNotNull();
}
}
But when i run this test, i get excpetion, what sensorRepository is not mock, it is null.
If i get mock right in test, like
SensorRepository sensorRepository1 = mock(SensorRepository.class);
SensorService sensorService1 = new SensorsServiceImpl(sensorRepository1);
it works correctly. Where can be a problem?
I solved it adding annotation #SpringBootTest

Mockito injecting mocks Spring Boot test

Hi I have a service class that contains mapper and repository:
#Service
public class ProductServiceImp implements ProductService {
#Autowired
private ProductRepository repository;
#Autowired
private WarehouseApiMapper mapper;
public ProductServiceImp(ProductRepository repository) {
this.repository = repository;
}
}
Repository:
#Repository
public interface ProductRepository extends JpaRepository<Product, Integer> {
}
Mapper:
#Mapper(componentModel = "spring")
public interface WarehouseApiMapper {
WarehouseApiMapper mapper = Mappers.getMapper(WarehouseApiMapper.class);
Product ProductDtoToProduct(ProductDto productDto);
ProductDto ProductToProductDto(Product product);
}
In test class I would like to inject mock repository and autowired mapper
Here is my test class:
#SpringBootTest
public class ProductServiceTest {
#Mock
ProductRepository repository;
#InjectMocks
ProductServiceImp service;
#ParameterizedTest
#MethodSource("provideParametersProductUpdate")
void assert_that_product_is_updated_correctly(String productName, BigDecimal productPrice) {
Product oldProduct = new Product("Product that does not exist", BigDecimal.valueOf(1000000), null);
oldProduct.setId(1);
Mockito.when(repository.findById(1)).thenReturn(Optional.of(oldProduct));
Product newProduct = new Product(productName, productPrice, null);
newProduct.setId(1);
ProductDto updatedProduct = service.updateProduct(newProduct);
Assertions.assertEquals(productPrice, updatedProduct.getPrice());
Assertions.assertEquals(productName, updatedProduct.getName());
}
private static Stream<Arguments> provideParametersProductUpdate() {
return Stream.of(
Arguments.of("dark chocolate", BigDecimal.valueOf(3.2)),
Arguments.of("chewing gum", BigDecimal.valueOf(1.2)),
Arguments.of("lollipop", BigDecimal.valueOf(4.0))
);
}
}
Code throws NullPointerException when is trying to map object in service method.
Somebody knows how can I inject this? Thanks for ur answers
If you want to create just a Mockito test you could use the annotation #RunWith(MockitoJUnitRunner.class) instead of #SpringBootTest.
But if you want to create a Spring Boot integration test then you should use #MockBean instead of #Mock and #Autowired instead of #InjectMocks.

JUnit test case not returning proper values when used when then return condition

Here is the code I am using.
The test class:
#ExtendWith(MockitoExtension.class)
#SpringBootTest
public class XTest{
#Mock
XRepository xRepository ;
#Mock
XServiceImpl xServiceImpl ;
X x = new X();
XC xC= new XC();
List<X> lX= new ArrayList<X>();
#BeforeEach
void createProcedure(){
x.setId((long)1);
x.setDescription("First one");
x.setValue("10");
xC.setCode("X");
x.setCategory(xC);
lX.add(x);
}
#Test
void testGetXByCode() {
Mockito.when(xRepository.findByCode(Mockito.anyString())).thenReturn(lX);
List<X> xL= xServiceImpl.getProcedureByCode("X");
System.out.println(lX.size());
assertEquals(1,xL.size());
assertNotEquals("Y", xL.get(0).getCategory().getCode() );
}
}
My service implementation class:
#Service
public class XServiceImpl implements XService {
private final XRepository xRepository;
#Autowired
public XServiceImpl(XRepository xRepository) {
this.xRepository = xRepository;
}
#Transactional
public List<X> getXByCode(String code) {
List<X> x= new ArrayList<>();
try {
x= xRepository.findByCode(code);
if (!x.isEmpty()) {
return x;
}
} catch (Exception ex) {
}
return null;
}
}
And my repository code is as follows:
#Repository
public interface XRepository extends JpaRepository<X, Long>{
public Optional<X> findById(Long id);
}
Both the test cases seem to be failing. Can anyone help me out with this?
The actual size of the list is 1 which is being printed. But when then return doesn't seem to be returning the same one.
#Mock creates mock. You should annotate XServiceImpl with #InjectMocks so that creates an instance of the class and injects the mocks that are created with the #Mock annotations (such as XRepository).
#InjectMocks
XServiceImpl xServiceImpl;

Spring Boot Service Junit Mockito issue

I have written Junit for the service. mocking dao.
Service method return type in EmployeeDTO.
Dao return type is Employee.
problem is employee to employeeDto conversion failed in test case.
when(dao.method()).thenReturn(new Employee), so on call od service.method() I am facing issue since dozer is in between to convert employee to employeedto in the actual code.
any suggestions to fix this.
#SpringBootTest(classes = { EmployeeSearchService.class, EmployeeDao.class })
public class EmployeeSearchServiceTest {
#Mock // will create a mock implementation for the EmployeeDao
EmployeeDao employeeDao;
#InjectMocks // will inject the mocks marked with #Mock to this instance when it is created.
private EmployeeSearchService employeeSearchService ;
#Mock
private DozerBeanMapper dozerBeanMapper;
#Before
public void setUp() throws Exception {
MockitoAnnotations.initMocks(this);
}
#DisplayName("fetchEmployees with valid data")
#Test
public void testfetchEmployeesWithValidData() throws IOException {
when(employeeDao.fetchEmployees()).thenReturn(Stream
.of(new Employee((long) 1, "James", "Java", "Manager", "Google"),
new Employee((long) 2, "Richard", "C++", "Manager", "Microsfot"))
.collect(Collectors.toList()));
//when(dozer.map(Mockito.any(), Mockito.any())).thenReturn(employeeDTO);
System.out.println(employeeSearchService.fetchEmployees());
assertEquals(4, employeeSearchService.fetchEmployees().size());
}
}
#Service
public class EmployeeSearchServiceImpl implements EmployeeSearchService {
#Autowired
EmployeeDao employeeDao;
#Autowired
DozerBeanMapper dozerBeanMapper;
#Override
#Logging
public List<EmployeeDTO> fetchEmployees() throws IOException {
List<Employee> aEmployeeList = employeeDao.fetchEmployees();
List<EmployeeDTO> aEmployeeDTOList= aEmployeeList.stream().map(emp ->
dozerBeanMapper.map(emp,
EmployeeDTO.class)).collect(Collectors.toList());
if (aEmployeeList.isEmpty()) {
throw new EmployeeNotfoundException("Employee Details Not Available");
}
return aEmployeeDTOList;
}
}
#Repository
public class EmployeeDaoImpl implements EmployeeDao {
#Override
#Logging
public List<Employee> fetchEmployees() throws IOException {
List<String> aFileList=fileUtils.getFileContent(EmployeeSearchConstants.EMPLOYEE_DETAILS_PATH);
List<Employee> aEmployeList = getEmployee(aFileList);
if (aEmployeList.isEmpty()) {
throw new EmployeeNotfoundException("Employee Details Not Available");
}
return aEmployeList;
}
}
If I understand you correctly your issue is that you are looking for a way to convert your Employee into a EmployeeDTO object, which in your code is done using dozerBeanMapper.map(emp, EmployeeDTO.class).
One option would be to change the EmployeeSearchServiceImpl and use Constructor Injection instead of Field Injection. This way you could simply use the real dozer class to do the mapping (by manually passing the mock for employeeDao and the real dozerBeanMapper).
Constructor Injection is done by moving the #Autowired to the constructor instead of the fields. Depening on your spring version and in case you only have one constructor for the class you might be able to omit the annotation. For more information check here.
EmployeeDao employeeDao;
DozerBeanMapper dozerBeanMapper;
#Autowired
public EmployeeSearchServiceImpl(EmployeeDao employeeDao, DozerBeanMapper dozerBeanMapper) {
this.employeeDao = employeeDao;
this.dozerBeanMapper = dozerBeanMapper;
}
Another option would be to use Mockito's thenAnser functionality. However
you still require something to do the conversion for you.
when(dozerBeanMapper.map(Mockito.any(), Mockito.any())).thenAnswer(new Answer<EmployeeDTO>() {
public EmployeeDTO answer(InvocationOnMock invocation) {
Employee employee = (Employee) invocation.getArguments()[0];
// convert to EmployeeDTO
EmployeeDTO dto = ...
return dto;
}
});

Spring injection: #MockBean #Repository is not injected

I'm trying to #MockBean a #Repository annotated class:
#Repository
public interface ApplicationDao extends MongoRepository<Application, String> {}
I'm injecting it into a #Service annotated class:
#Service
public class AuthorizationService {
private ApplicationDao appsDao;
private List<Application> allowedApplications;
#Autowired
public AuthorizationService(ApplicationDao appsDao) {
this.appsDao = appsDao; //<<MOCKED INJECTED BEAN>>
this.fillApplications();
}
private void fillApplications() {
this.appsDao.findAll() //<<MOCKED method>>
.forEach(entry -> {
this.allowedApplications.put(entry.getName(), entry);
});
}
public bool isAuthorized(Application application) {
return this.allowedApplications
.stream()
.anyMatch(app -> app.getId().equals(application.getId()));
}
}
My test mocking configuration looks like:
#RunWith(SpringRunner.class)
#SpringBootTest()
public class GroupReferencesTest {
private #Autowired AuthorizationService;
private #MockBean ApplicationDao applicationDao;
#Before
public void setUp() {
Application testApplication = new Application();
testApplication.setName("test-application");
List<Application> allowedApplications = new ArrayList<Application>();
allowedApplications.add(testApplication);
Mockito
.when(this.applicationDao.findAll())
.thenReturn(allowedApplications);
}
#Test
public void test() {
Application app = new Application();
app.getId("test-application");
assertTrue(this.authorizationService.isAuthorized(app)); //<<FAILS>>
}
}
Nevertheless, my mocked object is not injected. I mean, when my AuthorizationService calls its injected ApplicationDao is returns an empty list instead of my mocked list.
I've tried to use #MockBean(name="applicationDao") as well. The behavior is the same.
I've also tried to configure my mocked bean using this code:
#TestConfiguration
public class RestTemplateTestConfiguration {
#Bean("applicationDao")
#Primary
public static ApplicationDao mockApplicationDao() {
ApplicationDao mock = Mockito.mock(ApplicationDao.class);
Application testApplication = new Application();
testApplication.setName("test-application");
List<Application> allowedApplications = new ArrayList<Application>();
allowedApplications.add(testApplication);
Mockito
.when(mock.findAll())
.thenReturn(allowedApplications);
return mock;
}
}
However, it doesn't works right.
Application class is:
public class Application {
private String id;
//setters & getters
}
Any ideas?
First things first - the type of test. Answer: Unit test.
You are starting Spring context that manages a lifecycle of AuthorizationService and then you are trying to inject mock. What really happens is that Spring IoC container is injecting a real ApplicationDao (the one managed by Spring IoC container) into the AuthorizationService.
Solution:
Manage lifecyle of AuthorizationService by your test runner (like MockitoJUnitRunner and inject ApplicationDao mock into it):
#RunWith(MockitoJUnitRunner.class)
public class GroupReferencesTest {
private #InjectMocks AuthorizationService authorizationService;
private #Mock ApplicationDao applicationDao;
#Before
public void setUp() {
Application testApplication = new Application();
testApplication.setName("test-application");
List<Application> allowedApplications = new ArrayList<Application>();
allowedApplications.add(testApplication);
Mockito
.when(this.applicationDao.findAll())
.thenReturn(allowedApplications);
}
#Test
public void test() {
Application app = new Application();
app.getId("test-application");
assertTrue(this.authorizationService.isAuthorized(app));
}
}
Working example
#RunWith(SpringRunner.class)
#SpringBootTest(classes = {AuthorizationService.class})
public class GroupReferencesTest {
#Autowired
private AuthorizationService;
#MockBean
private ApplicationDao applicationDao;
#Test
public void test() {
//given
Mockito.when(applicationDao.findAll()).thenReturn(emptyList());
//when & then
assertTrue(authorizationService.isAuthorized(app));
}
}

Resources