Junit Mocking throwing Null pointer - junit

I'm trying to mock the below service class.
I have created a separate Config bean which I'm calling as you can see below in the code:-
#Component
public class CrawlerService implements CrawlerServiceInterface {
private static final Logger LOGGER = LoggerFactory.getLogger(CrawlerService.class);
private final CrawlConfig config;
#Autowired
CrawlerFactory crawlerFactory;
#Autowired
public CrawlerService(#Qualifier(value = "CrawlerConfig") CrawlConfig config) {
this.config = config;
}
#Value("${com.prudential.noOfCrawlers}")
private int numberOfCrawlers;
#Override
public Object crawlService(String URL, int max) throws Exception {
LOGGER.info("In Service Class");
this.config.setMaxPagesToFetch(max);
PageFetcher pageFetcher = new PageFetcher(config);
RobotstxtConfig robotstxtConfig = new RobotstxtConfig();
RobotstxtServer robotstxtServer = new RobotstxtServer(robotstxtConfig, pageFetcher);
CrawlController controller = new CrawlController(config, pageFetcher, robotstxtServer);
controller.addSeed(URL);
controller.start(crawlerFactory, numberOfCrawlers);
List<Object> crawlersLocalData = controller.getCrawlersLocalData();
LOGGER.info("End of Service Class");
return crawlersLocalData;
}
}
The problem is that I'm getting a null pointer exception in this.config.setMaxPagesToFetch.
What am I doing wrong?
If I mocked some dependent object with #Mock annotation, does it mean it won't allow the value to be changed?
Here is the test class:-
List<Object> obj=new ArrayList<Object>();
#Mock
private CrawlConfig config;
#Mock
CrawlerFactory crawlerFactory;
#Mock
CrawlController controller;
#InjectMocks
CrawlerService crawlerService = new CrawlerService(config);
#Before
public void setUp() throws Exception {
MockitoAnnotations.initMocks(this);
}
#Test
public void testService() throws Exception {
when(controller.getCrawlersLocalData()).thenReturn(obj);
assertEquals(crawlerService.crawlService("https://vogella.com", 10), obj);
}

Here you have the problem with mock creating order. First of all, let's see what is happening here:
First, you are declaring some fields. In this case, you are declaring private CrawlConfig config and CrawlerService crawlerService. But crawlerService you don't just declare but initialize as well.
When you initialize it, you are passing as a dependency to it CrawlConfig config which is null.
Then MockitoAnnotations.initMocks(this) start doing it's magic. What does it do? It initializes all the fields annotated with #Mock, then it tries to initialize the #InjectMocks if it's not already initialized. In your case it is already initialized, so mockito won't initialize it and will use the instance which you created.
After that the mock injection takes part. Mockito will try to use any of it's strategy to inject mocks. You can read more about it in #InjectMocks javadoc. So in your case, mockito will try to use property setter or field injection. However, the CrawlConfig config in your CrawlerService is declared final, and mockito will ignore this field, as for this type of injection mockito ignores final or static fields.
So here you have created an instance of CrawlerService with dependency CrawlConfig config which is null and mockito won't do anything about it.
1) You can mock the CrawlConfig config by yourself before mockito is going to:
private CrawlConfig config = Mockito.mock(CrawlConfig.class);
#InjectMocks
CrawlerService crawlerService = new CrawlerService(config);
2) You can omit the initialization of the CrawlerService and rely on mockito:
#Mock
private CrawlConfig config = Mockito.mock(CrawlConfig.class);
#InjectMocks
CrawlerService crawlerService;
Each of these methods should work.
You can as well remove the final declaration from your CrawlerService and it will also work. But as for me, the two methods above are better options.

Related

autowired ObjectMapper is null during #DataJpaTest

I want to test my implementation for AttributeConverter using #DataJpaTest.
test code
#RunWith(SpringRunner.class)
#DataJpaTest
#AutoConfigureTestDatabase(replace = AutoConfigureTestDatabase.Replace.NONE)
class FooRepositoryTest {
#Autowired
private FooRepository repository;
#Test
void getPojoTest(){
FooEntity fooEnity= repository.findById("foo");
FooPojo fooPojo = fooEntity.getJsonPojo()
//some assertion
}
}
Entity
#Entity
#Data
#NoArgsConstructor
public class FooEntity{
....
#Column(columnDefinition= "JSON")
#Convert(converter = FooConverter.class)
private FooPojo data;
....
}
Attribute Converter
public class FooConverter implements AttributeConverter<FooPojo, String> {
#Autowired
private ObjectMapper mapper;
#SneakyThrows
#Override
public String convertToDatabaseColumn(FooPojo attribute) {
return mapper.writeValueAsString(attribute);
}
#SneakyThrows
#Override
public FooPojo convertToEntityAttribute(String dbData) {
return mapper.readValue(dbData, FooPojo.class);
}
}
with my code above, when I run getPojoTest(), the #autowired OjbectMapper in Converter is null. When I try the same test with #SpringBootTest instead, it works just fine. I wonder is there any walk-around to use #DataJpaTest and ObjectMapper together.
A better alternative compared to creating your own ObjectMapper is adding the #AutoConfigureJson annotation:
#DataJpaTest
#AutoConfigureTestDatabase(replace = AutoConfigureTestDatabase.Replace.NONE)
#AutoConfigureJson
public void FooRepositoryTest {
}
This is also what #JsonTest uses.
From Docs:
#DataJpaTest can be used if you want to test JPA applications. By
default it will configure an in-memory embedded database, scan for
#Entity classes and configure Spring Data JPA repositories. Regular
#Component beans will not be loaded into the ApplicationContext.

Unit Test class not running properly - Mocking Interfaces

I have a simple Controller class like below:-
#RestController
public class CrawlerAppController {
private static final Logger LOGGER = LoggerFactory.getLogger(CrawlerAppController.class);
#Autowired
private CrawlerServiceInterface crawlerService;
/* The response time of the crawling operation is directly proportional to the no of pages
* we want to crawl. Keeping a default value of 10 so we can view the results quicker.
* author: Arunava Paul
*/
#RequestMapping(value = "/crawl", method = { RequestMethod.GET })
public Object crawlUrl(#RequestParam(value = "URL") String URL,
#RequestParam(value = "max", defaultValue = "10") int maxPages) throws Exception {
if(!URL.startsWith("https://"))
URL="https://"+URL;
LOGGER.info("Request Received. Domain "+URL+" Pages to be Crawled "+maxPages);
return crawlerService.crawlService(URL, maxPages);
}
}
I have written a Junit class like below:-
#RunWith(PowerMockRunner.class)
public class CrawlerAppControllerTest {
Object obj=new Object();
#Spy
#InjectMocks
private CrawlerServiceInterface crawlerService = Mockito.any(CrawlerService.class);
#InjectMocks
CrawlerAppController appController = new CrawlerAppController();
#Before
public void setUp() throws Exception {
MockitoAnnotations.initMocks(this);
}
#Test
public void testController() throws Exception {
when(crawlerService.crawlService("https://vogella.com", 20)).thenReturn(obj);
assertEquals(appController.crawlUrl("vogella.com",20), obj);
}
}
It's always going into the Service class and the when statement is not running.
Can someone please advise what have I done wrong. Below error comes if I run Junit.
You should declare crawlerService like this:
#Mock
private CrawlerServiceInterface crawlerService;
The declaration of crawlerService in the test class should be:
#Mock
private CrawlerServiceInterface crawlerService;

Mock Class instance in java

Is there a way to mock Class instance in java
#Autowired
private ApplicationContext context;
public <T> T search(Class<? extends JpaSpecificationExecutor<ENTITY>>
specExecutor,
Class<? extends Converter<DTO, ENTITY>> objConverter) {
JpaSpecificationExecutor jpaSpecificationExecutor = context.getBean(specExecutor);
Converter converter = context.getBean(objConverter);
}
I have to unit test the above method, i am using Mockito.
The issue is, when i use:
Mockito.when(context.getBean(any(Class.class))).thenReturn(new MyJpaSpecificationExecutor());
The above will not work for context.getBean(objConverter); // ClassCastException
Is there a way in Mockito or PowerMockito to achieve this?

How do I autowire a field with a real implementation while mocking another field?

I'm trying to unit test a Spring-boot controller and one of my #Autowired fields is coming back null.
I have two autowired fields in this controller:
public class UserProfileController{
#Autowired
private UserProfileService profileService;
#Autowired
private IDataValidator dataValidatorImpl;
My test class is as follows:
#RunWith(SpringJUnit4ClassRunner.class)
#WebIntegrationTest
#SpringApplicationConfiguration(classes = UserProfileServiceApplication.class)
public class ControllerTest {
private MockMvc mockMvc;
#Mock
UserProfileService profileServiceMock;
#Autowired
ApplicationContext actx;
#InjectMocks
private UserProfileController profileController;
#Before
public void setup() {
// Process mock annotations
String[] asdf = actx.getBeanDefinitionNames();
for (int i = 0; i < asdf.length; i++){
System.out.println(asdf[i]);
}
MockitoAnnotations.initMocks(this);
// Setup Spring test in standalone mode
this.mockMvc = MockMvcBuilders.standaloneSetup(profileController).build();
}
/**
* All this does is verify that we return the correct datatype and HTTP status
* #throws Exception
*/
#Test
public void testGetProfileSuccess() throws Exception {
Mockito.when(profileServiceMock.getProfile(Mockito.any(HashMap.class))).thenReturn(new HashMap<String, Object>());
mockMvc.perform(get("http://localhost:8095/UserName?tenantId=tenant1"))
.andExpect(status().isOk())
.andExpect(content().contentType(TestUtil.APPLICATION_JSON_UTF8));
//verify profileService was only used once
Mockito.verify(profileServiceMock, Mockito.times(1)).getProfile(Mockito.any(HashMap.class));
//verify we're done interacting with profile service
Mockito.verifyNoMoreInteractions(profileServiceMock);
}
If I leave IDataValidator untouched in the test class, it comes up null and I get a NPE. If I #Spy the DataValidatorImpl, it cannot find properties from the Spring environment that it needs to work.
How can I just let the IDataValidator autowire itself and maintain its spring environment context as if I were just running the application normally?
When I print all beans in my #Before setup() method, I can see DataValidationImpl in the list.
When you mock your controller with
MockMvcBuilders.standaloneSetup(profileController).build();
the controller is replaced in the context. Since you did not inject any IDataValidator in it, it is null.
The simplest solution is to autowired the real IDataValidator into your test class and inject it into the controller.
In your controller:
public class UserProfileController{
private UserProfileService profileService;
private IDataValidator dataValidatorImpl;
#Autowired
public UserProfileController(UserProfileService profileService, IDataValidator dataValidatorImpl) {
this.profileService = profileService;
this.dataValidatorImpl = dataValidatorImpl;
}
And in your test :
#RunWith(SpringJUnit4ClassRunner.class)
#WebIntegrationTest
#SpringApplicationConfiguration(classes = UserProfileServiceApplication.class)
public class ControllerTest {
private MockMvc mockMvc;
private UserProfileService profileService;
#Autowired
private IDataValidator dataValidator;
#Before
public void setup() {
UserProfileService profileService = Mockito.mock(UserProfileService.class);
UserProfileController controller = new UserProfileController(profileService, dataValidator);
// Setup Spring test in standalone mode
this.mockMvc = MockMvcBuilders.standaloneSetup(controller).build();
}
}
If I understand correctly, you want to inject UserProfileController with real Validator and mock Service.
In this case I suggest to use #ContextConfiguration annotaion which allows to configure context in the test. You'll need to create a Configuration class:
#RunWith(SpringJUnit4ClassRunner.class)
#WebIntegrationTest
#SpringApplicationConfiguration(classes = UserProfileServiceApplication.class)
public class ControllerTest {
private MockMvc mockMvc;
#Mock
UserProfileService profileServiceMock;
#Autowired
ApplicationContext actx;
//comment this line out
//#InjectMocks
#Autowired
private UserProfileController profileController;
#Before
public void setup() {
// Process mock annotations
String[] asdf = actx.getBeanDefinitionNames();
for (int i = 0; i < asdf.length; i++){
System.out.println(asdf[i]);
}
//comment this line out
//MockitoAnnotations.initMocks(this);
#Configuration
public static class Config {
//wire validator - if it is not wired by other configurations
#Bean
Validator validator() {
return new Validaor();
}
//wire mock service
#Bean
public UserProfileService profileService() {
return mock(UserProfileService.class);
}
}
Okay, I swear I did this the first time but when trying to recreate the error thrown for jny it actually worked.
My solution is to inject via #Spy annotation and get the bean from the ApplicationContext in my #Before setup method.
public class ControllerTest {
private MockMvc mockMvc;
#Mock
UserProfileService profileServiceMock;
#Spy
IDataValidator dataValidator;
#Autowired
ApplicationContext actx;
#InjectMocks
private UserProfileController profileController;
#Before
public void setup() {
dataValidator = (IDataValidator) actx.getBean("dataValidatorImpl");
MockitoAnnotations.initMocks(this);
// Setup Spring test in standalone mode
this.mockMvc = MockMvcBuilders.standaloneSetup(profileController).build();
}

JDBI mapper JUnit tests

I'd like to unit test my JDBI mapper classes since not all do trivial property mapping.
My testing class looks as follows:
public class IdentRuleMapperTest {
#Mock
ResultSet resultSet;
#Mock
ResultSetMetaData resultSetMetaData;
#Mock
StatementContext ctx;
IdentRuleMapper mapper;
#Before
public void setup() {
mapper = new IdentRuleMapper();
}
#Test
public void mapTest() throws SQLException {
Mockito.when(resultSet.getString("ID")).thenReturn("The ID");
Mockito.when(resultSet.getString("NAME")).thenReturn("The name");
Mockito.when(resultSet.getString("REGULATION")).thenReturn("CRS");
Mockito.when(resultSet.getString("JSON_ACTIONS_STRING")).thenReturn("the json string");
IdentRule identRule = mapper.map(0, resultSet, ctx);
}
}
The test throws NPE on the line
Mockito.when(resultSet.getString("ID")).thenReturn("The ID");
Anyone can point out to me why this won't work?
The annotation #Mock does not create the mock objects by itself. You have to add Mockito's JUnit rule as a field to your test
#Rule
public MockitoRule rule = MockitoJUnit.rule();
or use its JUnit runner
#RunWith(MockitoJUnitRunner.class)
public class IdentRuleMapperTest {
...
or create the mocks in an #Before method using MockitoAnnotations
#Before
public void initMocks() {
MockitoAnnotations.initMocks(this);
}
when setting the expectations on mock objects, use Matchers for arguments matching.
Mockito.when(resultSet.getString( Matchers.eq("ID"))).thenReturn("The ID");