JDBI mapper JUnit tests - junit

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

Related

how to mock restTemplate getForObject

I want to test the restTemplate.getForObject method using a mock but having issues. I'm new with Mockito, so I read some blogs about testing restTemplate using Mockito but still can not write a successful test.
The class to test is :
package rest;
#PropertySource("classpath:application.properties")
#Service
public class RestClient {
private String user;
// from application properties
private String password;
private RestTemplate restTemplate;
public Client getClient(final short cd) {
restTemplate.getInterceptors().add(new BasicAuthenticationInterceptor(user, password));
Client client = null;
try {
client = restTemplate.getForObject("http://localhost:8080/clients/findClient?cd={cd}",
Client.class, cd);
} catch (RestClientException e) {
println(e);
}
return client;
}
public RestTemplate getRestTemplate() {
return restTemplate;
}
public void setRestTemplate(final RestTemplate restTemplate) {
this.restTemplate = restTemplate;
}
}
My test class :
package test;
#PropertySource("classpath:application.properties")
#RunWith(MockitoJUnitRunner.class)
public class BatchRestClientTest {
#Mock
private RestTemplate restTemplate;
#InjectMocks
private RestClient restClient;
private MockRestServiceServer mockServer;
#Before
public void setUp() throws Exception {
}
#After
public void tearDown() throws Exception {
}
#Test
public void getCraProcessTest() {
Client client=new Client();
client.setId((long) 1);
client.setCd((short) 2);
client.setName("aaa");
Mockito
.when(restTemplate.getForObject("http://localhost:8080/clients/findClient?cd={cd},
Client.class, 2))
.thenReturn(client);
Client client2= restClient.getClient((short)2);
assertEquals(client, client2);
}
public RestTemplate getRestTemplate() {
return restTemplate;
}
public void setRestTemplate(RestTemplate restTemplate) {
this.restTemplate = restTemplate;
}
public RestClient getRestClient() {
return restClient;
}
public void setRestClient(RestClient restClient) {
this.restClient = restClient;
}
}
It is returning null and not the expected client, the restTemplate for Object class works fine. I want just to write the test . Am I missing something or doing the test wrong way?
Thanks for any guidance.
Use this instead:
Mockito.when(restTemplate.getForObject(
"http://localhost:8080/clients/findClient?cd={id}",
Client.class,
new Object[] {(short)2})
).thenReturn(client);
The third parameter is a varargs.
So you need to wrap into an Object[] in the test, otherwise Mockito is not able to match it. Note that this happens automatically in your implementation.
Also:
You forgot to terminate your url (missing closing ") in your examples in the question. Probably just a typo.
You used different url's in your implementation in your test: ...?cd={cd} instead of ...?cd={id}.(As previously pointed out by #ArnaudClaudel in the comments).
You did not define a behaviour for restTemplate.getInterceptors() so I would expect it to fail with a NullPointerException, when trying to add the BasicAuthenticationInterceptor.
Additionally you might want to check my answer here for another example of how to mock the getForObject method. Note that it does not include a case where any of the real parameters would be null.

Junit Mocking throwing Null pointer

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.

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;

How to write JUnit Test case

I am learning Junit testing on spring boot Application. my account controller method is depend on service class method. For that I used Mockito. I tried simple But here I am not getting how to write test case for following method? How I can use mockito.
can any one please help me for writing this test case?
AccountController
#RestController
#RequestMapping("/spacestudy/$ {InstituteIdentifier}/admin/account")
public class AccountController {
#Autowired
AccountService accService;
#GetMapping("/findAccountData")
public ResponseEntity<List<Tuple>> populateGridViews(#RequestParam(value="sClientAcctId",required=false) String sClientAcctId,
#RequestParam(value="sAcctDesc",required=false) String sAcctDesc,
#RequestParam(value="sInvestigatorName",required=false)String sInvestigatorName,
#RequestParam(value="sClientDeptId",required=false) String sClientDeptId) throws Exception {
return ResponseEntity.ok(accService.populateGridViews(sClientAcctId, sAcctDesc,sInvestigatorName,sClientDeptId));
}
}
AccountService
public List<Tuple> populateGridViews(String sClientAcctId, String sAcctDesc, String sInvestigatorName,
String sClientDeptId)throws Exception{
QAccount account = QAccount.account;
QDepartment department = QDepartment.department;
QAccountCPCMapping accountCPCMapping = QAccountCPCMapping.accountCPCMapping;
QInvestigator investigator = QInvestigator.investigator;
JPAQuery<Tuple> query = new JPAQuery<Tuple>(em);
query.select(Projections.bean(Account.class, account.sClientAcctId, account.sAcctDesc, account.sLocation,
Projections.bean(Department.class, department.sDeptName, department.sClientDeptId).as("department"),
Projections.bean(Investigator.class, investigator.sInvestigatorName).as("investigator"),
Projections.bean(AccountCPCMapping.class, accountCPCMapping.sCCPCode).as("accountCPC"))).from(account)
.innerJoin(account.department, department).innerJoin(account.accountCPC, accountCPCMapping)
.innerJoin(account.investigator, investigator);
if (StringUtils.isNotEmpty(sClientAcctId)) {
query.where(account.sClientAcctId.equalsIgnoreCase(sClientAcctId));
}
// code.......
return query.fetch();
}
AccountControllerTest
#RunWith(SpringRunner.class)
public class TestAccountController {
private MockMvc mockMvc;
#Mock
private AccountService accountService;
#InjectMocks
private AccountController accountController;
#Before
public void setup() {
mockMvc = MockMvcBuilders.standaloneSetup(accountController).build();
}
#Test
public void populateGridViewsTest() throws Exception {
//????
//????
}
}
It will be something like this:
#RunWith(SpringRunner.class)
public class TestAccountController {
private MockMvc mockMvc;
#Mock
private AccountService accountService;
#InjectMocks
private AccountController accountController;
#Before
public void setup() {
mockMvc = MockMvcBuilders.standaloneSetup(accountController).build();
}
#Test
public void populateGridViewsTest() throws Exception {
when(accountService.populateGridViews("foo","bar")).thenReturn(Arrays.asList(new Tuple("bazz"));
mockMvc.perform(get("/spacestudy/STACKOVERFLOW/admin/account/foo/bar"))
.andExpect(status().isOk())
.andExpect(jsonPath("someField").value("bazz"));
}
}
So basically you are replacing your service with mock and saying what it should return. In your particular case I don't see any reasons for unit testing this class, since it doesn't have any logic inside. But if you would have something like:
#GetMapping("/findAccountData")
public ResponseEntity<List<Tuple>> populateGridViews(...) throws Exception {
List<Tuple> result = accService.populateGridViews(...);
if(result==null){
return ResponseEntity.notFound();
}
return ResponseEntity.ok(result);
}
Then it would make more sense to test this class e.g.
1st test - mock your accService to return null and verify that response status is 404
2nd test - mock your accService to return not null and verify that response status is 200

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