#Autowired Bean is NULL in Spring Boot JUnit Test - spring-boot

I'm trying to write the unit test case for the below file.
RoleDataController.Java
#RestController
#RequestMapping("/updateRoleData")
public class RoleDataController extends ControllerBase {
#Autowired
public EntityManager entityManager;
public Session session = entityManager.unwrap(Session.class);
RoleData _roleData = new RoleData();
#RequestMapping("/getRoleData")
public String findRoleData(){
List roleList =_roleData.findRoleData(session,123456);
return JsonHelper.toJson(roleList);
}
}
RoleDataControllerTest.java
public class RoleDataControllerTest {
RoleData _roleData = new RoleData();
#Autowired
public EntityManager entityManager;
public Session session = entityManager.unwrap(Session.class);
#Test
public void findRoleData() throws Exception {
List roleList =_roleData.findRoleData(session, 123456);
Assert.assertNotNull(roleList);
}
}
I'm getting NullPointerException in the below line
public Session session = entityManager.unwrap(Session.class);
Please help to fix this.

Unit tests don't start the Spring context and so the #Autowired annotation won't work - no dependency injection will be done by Spring. You either want to write an integration test or mock the behaviour of other beans.

Related

Not able to mock jdbcTemplate(datasource) in springboot test class using testNG

I am getting a null pointer exception on jdbcTemplate object in this MyMain.java class while mocking the jdbcTemplate.update() method. I have used #Mock for this in the MyMainTest.java class. Here are my code snippets:
MyMain.java
#Component
public class MyMain {
private JdbcTemplate jdbcTemplate;
#Autowired
#Qualifier("myDatasource")
Datasource myDatasource;
#PostConstruct
public void initialize() {
jdbcTemplate = new JdbcTemplate(myDatasource);
}
public void saveData() {
jdbcTemplate.update("query", "parameter passing here"); // In this line only I am getting Nullpointer exception on jdbcTemplate.
}
}
MyMainTest.java
public class MyMainTest {
#Mock
JdbcTemplate jdbcTemplate;
#Test
public void saveDataTest() {
when(jdbcTemplate.update(Mockito.any(), Mockito.any()).thenReturn(1);
new MyMain().saveData();
}
}
I have tried several alternative ways and I am still getting this issue.
Note: I am using TestNG for running the test classes. It's a Spring Boot project.

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;
}
});

Mocked bean in spring unit test not wired to AutoWired dependency

I am trying to write unit test for a class which has an Autowired dependency.
public class User {
#Autowired
private ServiceContext serviceContext;
User() {}
public String getToken() {
return serviceContext.getToken();
}
My Unit Test class to test getToken() method
#RunWith(SpringJUnit4ClassRunner.class)
public class UserTest() {
#MockBean
private ServiceContext serviceContext;
#BeforeTest
private void setup() {
when(serviceContext.getToken()).thenReturn("Token");
}
#Test
public void test() {
User user = new User();
assertEquals(user.getToken(), "Token");
}
}
When I run this test, there is a NullPointerException in getToken() of User . It says the serviceContext variable is null.
Why cant the mock bean which I created in the test be autowired to the dependency in User class ?
I also tried this test code -
#RunWith(SpringJUnit4ClassRunner.class)
public class UserTest() {
#MockBean
private ServiceContext serviceContext;
#InjectMocks
User useer = new User();
#BeforeTest
private void setup() {
when(serviceContext.getToken()).thenReturn("Token");
}
#Test
public void test() {
assertEquals(user.getToken(), "Token");
}
}
This also gives a NullPointerException saying that the serviceContext dependency in User class is null.
How do I unit test my User class methods using a mocked ServiceContext bean and wiring it to the User objects ?
I am using annotation based spring configuration and dont want to start the spring container to test this.
For running my application, I am using this-
#Configuration
#EnableConfigurationProperties(ApiProperties.class)
public class ServiceConfiguration {
#Bean
#Scope(value = ConfigurableBeanFactory.SCOPE_SINGLETON, proxyMode = ScopedProxyMode.TARGET_CLASS)
ServiceContext serviceContext(ApiProperties properties, Parameter param) {
final ServiceContext serviceContext = new ServiceContext(properties, param);
return serviceContext;
}
Do I need to add this class in my #SpringBootTest ?
How does spring know which context should be created?
You've only defined that the test should run with spring, but spring has no clue from where to load the configurations.
You should use #SpringBootTest annotation if you want to rely on spring boot configuration resolution rules or at some #ContextConfiguration to specify manually the configurations to load.

Using #SpyBean with #Qualifier Spring Boot Test

I have 2 DataSources in my app.
So, to get the required JdbcTemplate, i use #Qualifier. But, when i do like below, the test runs... but stays waiting indefinitely, if there is any use of JdbcTemplate in the "Method Under Test".
#Service
#Transactional
public class SampleDatabaseService {
#Autowired
#Qualifier("firstDbJdbcTemplate")
private JdbcTemplate firstDbJdbcTemplate;
#Autowired
#Qualifier("secondDbJdbcTemplate")
private JdbcTemplate secondDbJdbcTemplate;
#Cacheable("status")
public Map<String, Device> readAllValidDeviceStatus() {
Map<String, Device> allDeviceStatuses = new HashMap<>();
//Stops at below line indefinitely if "SpyBean" is used
List<StatusDetail> statusDetails = firstDbJdbcTemplate
.query(SqlQueries.READ_DEVICE_STATUS, BeanPropertyRowMapper.newInstance(StatusDetail.class));
statusDetails
.stream()
.filter(deviceStatus -> deviceStatus.getName() != "Some Invalid Name")
.forEach(deviceStatus -> allDeviceStatuses
.put(deviceStatus.getName(), buildDevice(deviceStatus)));
return allDeviceStatuses;
}
/** More Stuff **/
}
and the Test :
#RunWith(SpringRunner.class)
#SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
#Transactional
#Rollback
#ActiveProfiles("test")
public class SampleDatabaseServiceTest {
#SpyBean
#Qualifier("firstDbJdbcTemplate")
private JdbcTemplate firstDbJdbcTemplate;
#Autowired
private SampleDatabaseService serviceUnderTest;
#Before
public void populateTables() {
//Insert some Dummy Records in "InMemory HSQL DB" using firstDbJdbcTemplate
}
#Test
public void testReadAllValidDeviceStatus() {
// When
Map<String, Device> allDeviceStatuses = serviceUnderTest.readAllValidDeviceStatus();
// Then
assertThat(allDeviceStatuses).isNotNull().isNotEmpty();
// More checks
}
/* More Tests */
}
But, when i replace the #SpyBean with #Autowired in Test, it works fine.
Why is it so? Any help is greatly appreciated. :)
Use it in below format
#MockBean(name = "firstDbJdbcTemplate")
private JdbcTemplate firstDbJdbcTemplate;

How to mock Spring Data and unit test service

I'm trying to unit test a service method. The service methods calls a spring data repository method to fetch some data. I want to mock that repository call, and supply the data myself. How to do that? Following Spring Boot documentation, when I mock the repository and call the repository method directly in my test code, the mock is working. But when I call the service method, which in turn would call the repository method, mocking isn't working. Below is the sample code:
Service class:
#Service
public class PersonService {
private final PersonRepository personRepository;
#Autowired
public PersonService(personRepository personRepository) {
this.personRepository = personRepository;
}
public List<Person> findByName(String name) {
return personRepository.findByName(name); // I'd like to mock this call
}
}
Test class:
#RunWith(SpringRunner.class)
#SpringBootTest
public class ApplicationTests {
// http://docs.spring.io/spring-boot/docs/current-SNAPSHOT/reference/htmlsingle/#boot-features-testing-spring-boot-applications-mocking-beans
#MockBean
private PersonRepository personRepository;
#Autowired
private PersonService personService;
private List<Person> people = new ArrayList<>();
#Test
public void contextLoads() throws Exception {
people.add(new Person());
people.add(new Person());
given(this.personRepository.findByName("Sanjay Patel")).willReturn(people);
assertTrue(personService.findByName("Sanjay Patel") == 2); // fails
}
}
For Spring Data repositories you need to specifiy the bean name. Mocking via type doesn't seem to work because the repository is a dynamic proxy at runtime.
The default bean name for PersonRepository is "personRepository", so this should work:
#MockBean("personRepository")
private PersonRepository personRepository;
Here's the complete test:
#RunWith(SpringRunner.class)
#SpringBootTest
public class ApplicationTests {
// http://docs.spring.io/spring-boot/docs/current-SNAPSHOT/reference/htmlsingle/#boot-features-testing-spring-boot-applications-mocking-beans
#MockBean("personRepository")
private PersonRepository personRepository;
#Autowired
private PersonService personService;
private List<Person> people = new ArrayList<>();
#Test
public void contextLoads() throws Exception {
people.add(new Person());
people.add(new Person());
given(this.personRepository.findByName("Sanjay Patel")).willReturn(people);
assertTrue(personService.findByName("Sanjay Patel") == 2); // fails
}
}
Probably the repository is marked with #MockedBean annotation. I do not know if Spring can auto wire by type if the repository is a mock.
You can define the #Bean method and return Mockito.mock(X.class), this should work.
Not sure you need spring for unit testing a service method though. A lighter approach would be to use solely Mockito with its #InjectMocks annotation.

Resources