How to avoid NullPointerException Junit RestTemplate - java

i'm working in spring project where i have a service that call another api using Restemplate , this service return just a string as a token and all works fine for me , this is my service :
#Service
public class AppServiceImpl {
#Value("${rest.appUrl}")
private String appUrl;
#Value("${credType}")
private String credType;
#Autowired
private RestTemplate restTemplate;
public String getToken() {
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED);
MultiValueMap<String, String> map = new LinkedMultiValueMap<>();
map.add("grant_type", credType);
HttpEntity<MultiValueMap<String, String>> request = new HttpEntity<MultiValueMap<String, String>>(map, headers);
ResponseEntity<TargetObject> response = restTemplate.exchange(appUrl, HttpMethod.POST, request, TargetObject.class);
TargetObject targetObject = response.getBody();
return "Bearer " + targetObject.getToken();
}
}
my problem is when i want to unit test this service i'm getting NullPointerException and i dont know why , this is my unit test :
#RunWith(SpringRunner.class)
public class AppServiceImplTest {
private AppService appService = new AppServiceImpl();
#Test
public void getTokenTest() {
String token = appService.getToken();
assertTrue(token != null);
}
}
the NullPointerException in this line :
ResponseEntity<TargetObject> response = restTemplate.exchange(appUrl, HttpMethod.POST, request, TargetObject.class);
do you have any idea what's the problem with my test ? i spent hours without any result
Thanks in advance

your problem is that in your service you autowire restTemplate, but in your test you initialize your class by yourself, and not through spring, and there for it is not initialized and remains null.
if you are initializing the service by yourself in the test, make sure to add a mocked instance of restTemplate. I suggest moving the autowire in the service to be c'tor based, and then it will be easy to do so in the test:
#Service
public class AppServiceImpl {
private String appUrl;
private String credType;
private RestTemplate restTemplate;
public AppServiceImpl(RestTemplate restTemplate, #Value("${credType}") String credType, #Value("${rest.appUrl}") String appUrl) {
this.restTemplate = restTemplate;
this.credType = credType;
this.appUrl = appUrl;
}
...
...
...
}
and later in your test:
#Mock private RestTemplate restTamplate;
private AppService appService;
#Before
public void setup() {
appService = new AppServiceImpl(restTamplate);
}

Use Mockito It will resolve your issue.
ResponseEntity<TargetObject> response = restTemplate.exchange(appUrl, HttpMethod.POST,
request, TargetObject.class);
junit for above code would be:
#Mock
private RestTemplate restTemplate;
TargetObject targetObject = new TargetObject();
targetObject.setToken("123456");
Mockito.when( restTemplate.exchange(Mockito.anyString(),Mockito.any(HttpMethod.class),
Mockito.any(HttpEntity.class),Mockito.any(TargetObject.class)).thenReturn(targetObject);

Related

Getting null response of resttemplate exchange in a mockito test

i am trying to write the mock test case for RestServiceImpl class. Below is the code. And i have a test class shown below RestServiceImplTest. When i run the test class it returning null from line restTemplate.exchange(UrlString, HttpMethod.POST, request, Object.class)
public class RestServiceImpl
private RestTemplate restTemplate;
#Autowired
public RestServiceImpl(RestTemplate restTemplate) {
this.restTemplate = restTemplate;
}
#Override
public ResponseEntity<Object> restService(DataRequest dataRequest) throws Exception {
ResponseEntity<Object> response = null;
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_JSON);
HttpEntity<DataRequest> request = new HttpEntity<>(dataRequest, headers);
try {
response = restTemplate.exchange(UrlString, HttpMethod.POST, request, Object.class);
} catch (Exception ex) {
throw ex;
}
return response;
}
}
Test class
#RunWith(SpringRunner.class)
public class RestServiceImplTest {
private RestServiceImpl restServiceImpl;
#Mock
private RestTemplate restTemplate;
#Mock
private DataRequest dataRequest;
#Before
public void setUp() {
restServiceImpl = new RestServiceImpl(restTemplate);
dataRequest = new DataRequest();
}
#Test
public void testRestServiceImplwithSuccess() throws Exception {
ResponseEntity<Object> resp = new ResponseEntity<Object>(HttpStatus.OK);
doReturn(resp).when(restTemplate).exchange(any(URI.class), any(HttpMethod.class), any(HttpEntity.class),
any(Class.class));
ResponseEntity<Object> mockResp = restServiceImpl.restService(DataRequest);
}
Can anybody tell me where is it going wrong.
Almost certainly this is happening because your doReturn is not being used due to the parameters not being met (your any() s).

Mockito test for postForEntity not working

I am trying to mock this method with postForEntity call -
public AuthorizeClient(RestTemplateBuilder builder, Config config) {
this.grantedUrl = config.grantedUrl();
this.restTemplate = HttpClientHelper.getRestTemplate(builder, authorizationConfig);
}
private final RestTemplate restTemplate;
private String grantedUrl;
public List<Permission> getPermissions(
PermissionsRequest permissionsRequest) {
try {
var headers = new HttpHeaders();
var request = new HttpEntity<PermissionsRequest>(permissionsRequest, headers);
var permissions = restTemplate.postForEntity(grantedUrl, request, Permission[].class);
return Arrays.asList(permissions.getBody());
} catch (HttpClientErrorException err) {
logger.error(err);
throw err;
}
}
Here is my test case -
RestTemplateBuilder restTemplateBuilder = new RestTemplateBuilder();
Config config = new Config();
#InjectMocks
AuthorizeClient authorizeClient = new AuthorizeClient(restTemplateBuilder, config);
#Mock
private RestTemplate restTemplate;
PermissionsRequest permissionsRequest;
ResponseEntity<Permission[]> expGrantedPermissions;
#Test
public void testAuthorizationPermissions() {
when(restTemplate.postForEntity(anyString(), any(), eq(Permission[].class))).thenReturn(expGrantedPermissions);
var res = authorizeClient.getAllGrantedPermissions(permissionsRequest);
assertNotNull(res);
}
I'm getting this error since url is not mocked properly -
[ERROR] testAuthorizationPermissions Time elapsed: 0.86 s <<< ERROR!
org.springframework.web.client.ResourceAccessException: I/O error on POST request for "http://localhost/v1/permissions": Connection refused (Connection refused); nested exception is java.net.ConnectException: Connection refused (Connection refused)
Now I'm getting this error. Looks like mock is still not observed..
java.lang.IllegalArgumentException: URI is not absolute
At this line -
var res = authorizeClient.getPermissions(permissionsRequest);
My AuthorizeClient is constructed like above..
Please suggest what am I missing. Frankly no clue :(
Thanks in advance
Although the RestTemplate is mocked, it doesn't take effect because the mock doesn't reach the tested object and the method authorizeClient::getAllGrantedPermissions uses its own implementation of RestTemplate.
The RestTemplate to be mocked must be also injected to the implementation which is supposed to use it, otherwise, the original, real, implementation is still used. Make the RestTemplate injectable:
class AuthorizeClient { // You haven't specified the class name
private final RestTemplate restTemplate;
private String grantedUrl;
public AuthorizeClient(RestTemplate restTemplate) { // Dependency injection through constructor
this.restTemplate = restTemplate;
}
public List<Permission> getPermissions(..) { .. }
}
And add #InjectMocks annotation to the tested object which should use mocked dependencies:
#Mock
private RestTemplate restTemplate;
#InjectMock // Injects all necessary #Mock objects
private AuthorizeClient authorizeClient; // An implementation, not an interface
#Test
public void testAuthorizationPermissions() {
Mockito.when(restTemplate.postForEntity(Mockito.anyString(), Mockito.any(), Mockito.any()))
.thenReturn(expGrantedPermissions);
// now it is assured the authorizeClient uses restTemplate and not its own one
var res = authorizeClient.getAllGrantedPermissions(permissionsRequest);
assertNotNull(res);
}

unit testing in spring boot giving error when exception thrown in service

So, I have this unit test that I need to run.
#MockBean
private AppServiceImpl appService;
#Test
public void shouldThrowExceptionWhenAppIdIsNull() throws Exception {
File inputFile = this.getJsonFile();
RequestDto requestDto = objectMapper.readValue(inputFile.getAbsoluteFile(),
RequestDto.class);
AppData appData = requestDto.getAppData();
appData.setAppId(null);
requestDto.setAppData(appData);
when(appService.getUrl(requestDto, "header")).thenThrow(new RequestNotValidException());
String payload = objectMapper.writeValueAsString(requestDto);
this.mockMvc.perform(post(Base_URL + "app/requesturl")
.contentType(contentType).content(payload).header(this.Header, "header"))
.andExpect(status().is4xxClientError());
}
Interface for service:
SO when I run this test, it throws an exception and doesn't actually assert the test here.
I have added #ResponseStatus(HttpStatus.BAD_REQUEST) on top of RequestNotValidException and it extends RunTimeException
And in the second test case, I get empty response. I tried this API vis Postman and I get the response. Everything works fine there.
#Test
public void getCardRegistration() throws Exception {
File inputFile = this.getJsonFile();
RequestDto requestDto = objectMapper.readValue(inputFile.getAbsoluteFile(), RequestDto.class);
ResponseDto responseDto = new ResponseDto();
responseDto.setURL(AuthUtils.randomStringToken(35));
given(appService.getRegistrationUrl(requestDto, "header")).willReturn(responseDto);
String payload = objectMapper.writeValueAsString(requestDto);
MvcResult mvcResult = this.mockMvc.perform(post(Base_URL + "app/requesturl")
.contentType(contentType).content(payload).header(this.Header, "header"))
.andReturn();
String contentAsString = mvcResult.getResponse().getContentAsString();
}
Controller content:
#Autowired
IAppService appService;
#RequestMapping(value = "/app/requesturl", method = RequestMethod.POST)
public ResponseDto getCardsRegistration(#RequestBody #Valid RequestDto requestDto, #RequestHeader(value="X-App-Name", required = true) String header) throws RequestNotValidException, JsonProcessingException {
log.info("Request received in controller: "+ mapper.writeValueAsString(cardRegistrationRequestDto));
log.info("Header value: "+ header);
return this.appService.getRegistrationUrl(requestDto, header);
}
Test Class:
#RunWith(SpringRunner.class)
#SpringBootTest
#AutoConfigureMockMvc
public class AppRestControllerTest {
protected String Base_URL = "/app";
protected String Header = "X-App-Name";
protected MediaType contentType = new MediaType(MediaType.APPLICATION_JSON.getType(),
MediaType.APPLICATION_JSON.getSubtype(),
Charset.forName("utf8"));
#Autowired
protected MockMvc mockMvc;
protected ObjectMapper objectMapper = new ObjectMapper();
#MockBean
private AppServiceImpl appService;
#Mock
private AppRegistrationRepository appRegistrationRepository;
#Before
public void setUp() throws Exception {
MapperFacade mapperFacade = new DefaultMapperFactory.Builder().build().getMapperFacade();
appService = new AppServiceImpl(appRegistrationRepository, mapperFacade);
}
What did I miss here?
Try to use
#RunWith(SpringRunner.class)
#WebMvcTest(YourController.class)
public class AppRestControllerTest {
Or
#RunWith(SpringRunner.class)
#SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.MOCK)
#AutoConfigureMockMvc
public class AppRestControllerTest {
In your tests

spring boot unit test assertion error

Working on a spring boot based Rest project I have a controller like this
which calls service and service layer call dao layer. Now I am writing unit test code for controllers. when I run this the error says
java.lang.AssertionError: expected:<201> but was:<415>
I don't know where I am doing wrong:
public class CustomerController {
private static final Logger LOGGER = LogManager.getLogger(CustomerController.class);
#Autowired
private CustomerServices customerServices;
#Autowired
private Messages MESSAGES;
#Autowired
private LMSAuthenticationService authServices;
#RequestMapping(value = "/CreateCustomer", method = RequestMethod.POST)
public Status createCustomer(#RequestBody #Valid Customer customer, BindingResult bindingResult) {
LOGGER.info("createCustomer call is initiated");
if (bindingResult.hasErrors()) {
throw new BusinessException(bindingResult);
}
Status status = new Status();
try {
int rows = customerServices.create(customer);
if (rows > 0) {
status.setCode(ErrorCodeConstant.ERROR_CODE_SUCCESS);
status.setMessage(MESSAGES.CUSTOMER_CREATED_SUCCESSFULLY);
} else {
status.setCode(ErrorCodeConstant.ERROR_CODE_FAILED);
status.setMessage(MESSAGES.CUSTOMER_CREATION_FAILED);
}
} catch (Exception e) {
LOGGER.info("Cannot Create the Customer:", e);
status.setCode(ErrorCodeConstant.ERROR_CODE_FAILED);
status.setMessage(MESSAGES.CUSTOMER_CREATION_FAILED);
}
return status;
}
}
The test for the CustomerController.
public class CustomerControllerTest extends ApplicationTest {
private static final Logger LOGGER = LogManager.getLogger(CustomerControllerTest.class);
#Autowired
private WebApplicationContext webApplicationContext;
private MockMvc mockMvc;
#MockBean
private CustomerController customerController;
#Before
public void setup() {
this.mockMvc = MockMvcBuilders.webAppContextSetup(webApplicationContext).build();
}
Status status = new Status(200,"customer created successfully","success");
String customer = "{\"customerFullName\":\"trial8900\",\"customerPhoneNumber\": \"trial8900\", \"customerEmailID\": \"trial8900#g.com\",\"alternateNumber\": \"trial8900\",\"city\": \"trial8900\",\"address\":\"hsr\"}";
#Test
public void testCreateCustomer() throws Exception {
String URL = "http://localhost:8080/lms/customer/CreateCustomer";
Mockito.when(customerController.createCustomer(Mockito.any(Customer.class),(BindingResult) Mockito.any(Object.class))).thenReturn(status);
// execute
MvcResult result = mockMvc.perform(MockMvcRequestBuilders.post(URL)
.contentType(MediaType.APPLICATION_JSON_UTF8)
.accept(MediaType.APPLICATION_JSON_UTF8)
.content(TestUtils.convertObjectToJsonBytes(customer))).andReturn();
LOGGER.info(TestUtils.convertObjectToJsonBytes(customer));
// verify
MockHttpServletResponse response = result.getResponse();
LOGGER.info(response);
int status = result.getResponse().getStatus();
LOGGER.info(status);
assertEquals(HttpStatus.CREATED.value(), status);
}
}
HTTP status 415 is "Unsupported Media Type". Your endpoint should be marked with an #Consumes (and possibly also #Produces) annotation specifying what kinds of media types it expects from the client, and what kind of media type it returns to the client.
Since I see your test code exercising your production code with MediaType.APPLICATION_JSON_UTF8, you should probably mark your endpoint as consuming and producing APPLICATION_JSON_UTF8.
Then you also need to make sure that there is nothing terribly wrong going on in your error handling, because in the process of catching the exceptions generated by your production code and generating HTTP responses, your error handling code may be generating something different, e.g. generating an error status response with a payload containing an HTML-formatted error message, which would have a content-type of "text/html", which would not be understood by your test code which expects json.
Use the below base test class for your setUp and converting json to string and string to json
#RunWith(SpringJUnit4ClassRunner.class)
#SpringBootTest(classes = Main.class)
#WebAppConfiguration
public abstract class BaseTest {
protected MockMvc mvc;
#Autowired
WebApplicationContext webApplicationContext;
protected void setUp() {
mvc = MockMvcBuilders.webAppContextSetup(webApplicationContext).build();
}
protected String mapToJson(Object obj) throws JsonProcessingException {
ObjectMapper objectMapper = new ObjectMapper();
return objectMapper.writeValueAsString(obj);
}
protected <T> T mapFromJson(String json, Class<T> clazz)
throws JsonParseException, JsonMappingException, IOException {
ObjectMapper objectMapper = new ObjectMapper();
return objectMapper.readValue(json, clazz);
}
}
Also verify that your post call has happened or not check the below sample
Mockito.doNothing().when(customerServices).create(Mockito.any(Customer.class));
customerServices.create(customer);
Mockito.verify(customerServices, Mockito.times(1)).create(customer);
RequestBuilder requestBuilder = MockMvcRequestBuilders.post(URI)
.accept(MediaType.APPLICATION_JSON).content(inputInJson)
.contentType(MediaType.APPLICATION_JSON);
MvcResult mvcResult = mvc.perform(requestBuilder).andReturn();
MockHttpServletResponse response = mvcResult.getResponse();
assertEquals(HttpStatus.OK.value(), response.getStatus());

EasyMock Controller Mapping and Status Code Tests

I'm trying to test my controller mapping and the response http status codes. Therefore I'm using the RequestMappingHandlerAdapter and the RequestMappingHandlerMapping.
My Controller
#Controller
#RequestMapping(value ="/user")
public class AdminSpringController {
#Autowired
public UserAdminService userService;
private final Logger log = LoggerFactory.getLogger(AdminSpringController.class);
#RequestMapping(method = RequestMethod.GET, consumes = "application/json", produces = "application/json")
#ResponseStatus(HttpStatus.OK)
public List<User> getUsers() {
log.trace("Request to get all users.");
return userService.getUsers();
}
}
and my Test class:
public class AdminSpringControllerTests {
AdminSpringController cut;
private MockHttpServletRequest request;
private MockHttpServletResponse response;
private RequestMappingHandlerAdapter adapter;
private RequestMappingHandlerMapping handlerMapping;
#Test
public void testGetSc() throws Exception{
adapter = new RequestMappingHandlerAdapter();
handlerMapping = new RequestMappingHandlerMapping();
MockHttpServletRequest request = new MockHttpServletRequest();
request.setMethod("GET");
request.setRequestURI("/user");
request.addHeader("Accept", "application/json");
MockHttpServletResponse response = new MockHttpServletResponse();
Object handler = handlerMapping.getHandler(request).getHandler();
ModelAndView mav = adapter.handle(request, response, handler);
assertNotNull(mav);
}
}
But I'm getting an NullPointerException in the row Object handler = ...
I simply want to test my mapping and then check the HTTP status codes from my response. Is this the right approach or is my test implementation totally wrong. For the tests I need to use EasyMock. As next step I wanted to test if the response status codes (response.getStatus()) is equals to SC_OK (200).
Thx for any help :)
I am using SpringMvc Test approach, mixed with EasyMock, which is a good approach.
#ContextConfiguration("ProjectFacadeTest-context.xml")
#RunWith(SpringJUnit4ClassRunner.class)
public class AdminSpringControllerTests {
...
private MockMvc mockMvc;
...
#Before
public void setUp() {
this.mockMvc = MockMvcBuilders.standaloneSetup(imageController).build();
}
EasyMock.expect(mockPersistedProjectService.getImages(EasyMock.anyLong())).andReturn(images);
EasyMock.replay(mockPersistedProjectService);
MvcResult result =
this.mockMvc.perform(get("/resources/projects/1000/images")).andExpect(content().type("application/json"))
.andExpect(status().isOk()).andReturn();
MockHttpServletResponse response = result.getResponse();
//VERIFY RESPONSE
EasyMock.verify(mockPersistedProjectService);
XML FILE
<bean id="mockArtifactService" class="org.easymock.EasyMock"
factory-method="createStrictMock" primary="true">
<constructor-arg value="com.xxxxxx.service.ArtifactService" />
</bean>

Categories