Usage of #Value properties in mockito test cases - java

I have a yml file where I am storing my variables. I am accessing these variables in my program by using #Value annotation. The problem comes when I am writing mock test cases for such methods, I get null pointer exception in my test method. I'm not sure where I am going wrong.
I am making use of #TestPropertySource right now. I need the correct way of doing this.
Here is what I have tried so far.
My yml file looks like this, with many properties in it:
car:
services:
clientId: abcde
authTokenUrl: ....
.....
public Class CarExecution(){
#Value("${car.services.clientId}")
private String clientId;
#Value("${car.services.authTokenUrl}")
private String authTokenUrl;
public String getAccessToken() {
HttpHeaders headers = new HttpHeaders();
headers.set(CONTENT_TYPE, "application/x-www-form-urlencoded");
headers.set(ACCEPT, APPLICATION_JSON);
HttpEntity<String> entity = new HttpEntity<>("grant_type=password" + "&client_id=" + clientId ,headers);
ResponseEntity<Access> response = restTemplate.exchange(authTokenUrl, HttpMethod.POST, entity,A.class);
return response.getBody().token_type + " " +
response.getBody().access_token;
}
}
#RunWith(MockitoJUnitRunner.class)
#TestPropertySource(properties = {
"car.services.clientId = clientId ","car.services.authTokenUrl = authTokenUrl",
})
public class CarTest {
#Value("${car.services.clientId}")
private String clientId;
#Value("${car.services.authTokenUrl}")
private String authTokenUrl;
mockServer = MockRestServiceServer.createServer(restTemplate);
HttpHeaders headers = new HttpHeaders();
headers.set(CONTENT_TYPE, "application/x-www-form-urlencoded");
headers.set(ACCEPT, APPLICATION_JSON);
HttpEntity<String> entity = new HttpEntity<>(
"grant_type=password&client_id=null", headers);
authTokenUrl = "";
new ResponseEntity<>("", HttpStatus.OK);
A access = new A();
access.access_token = "token";
access.token_type = "type";
response = new ResponseEntity<>(access, HttpStatus.OK);
Mockito.when(restTemplate.exchange(authTokenUrl, HttpMethod.POST, entity, A.class))
.thenReturn(response);

The problem might be with your Runner class as MockitoJUnitRunner doesn't initialise any beans or #Value annotations.
Spring's answer to it is SpringJUnit4ClassRunner which does these bits for you (documentation here).
Try replacing #RunWith(MockitoJUnitRunner.class) with #RunWith(SpringJUnit4ClassRunner.class).

Related

How to test restclient using RestTemplate and JUnit?

I am new to JUNIT and using RestTemplate to call my service, I'm getting 200 response for the same. But, I can't test the class using JUnit. Tried different approaches and getting 400 and 404. I want to post the request body (json) and test the status. Please let me know if there is any issue.
/**
* Rest client implementation
**/
public class CreateEmailDelegate implements CDM {
#Autowired
private RestTemplate restTemplate;
private String url = "http://example.com/communications/emails";
public ResponseEntity<CDResponse> createEmail(CDMEmailRequest cDRequest) throws UnavailableServiceException, InvalidInputException {
HttpHeaders httpHeaders = new HttpHeaders();
httpHeaders.set("SR_API_Key", SR_API_KEY);
httpHeaders.set("consumerIdentification", CONSUMER_IDENTIFICATION);
httpHeaders.setContentType(MediaType.APPLICATION_JSON);
HttpEntity< CDMEmailRequest > cDRequestEntity = new HttpEntity<>( cDRequest, httpHeaders);
ResponseEntity< CDResponse > cDResponse = null;
try {
cDResponse = restTemplate.postForEntity(url, cDRequestEntity, CDResponse.class);
} catch (Exception e) {
LOGGER.error(e.getMessage());
throw e;
}
return cDResponse;
}
}
My Test class which return 404 status instead of 200
#RunWith(SpringJUnit4ClassRunner.class)
public class CreateEmailCommunicationDelegateTest {
#Before
public void setup() {
httpHeaders = new HttpHeaders();
httpHeaders.set("SR_API_Key", SR_API_KEY);
httpHeaders.set("consumerIdentification", CONSUMER_IDENTIFICATION);
httpHeaders.setContentType(MediaType.APPLICATION_JSON);
DefaultMockMvcBuilder builder = MockMvcBuilders.webAppContextSetup(this.wac);
this.mockMvc = builder.build();
}
public void testResponse() throws Exception, HttpClientErrorException, JsonProcessingException {
String url = "http://example.com/CommunicationDeliveryManagement-Service-1.0.0/communications/emails";
CDMEmailRequest anObject = new CDMEmailRequest();
ResultMatcher ok = MockMvcResultMatchers.status().isOk();
ObjectMapper mapper = new ObjectMapper();
mapper.configure(SerializationFeature.WRAP_ROOT_VALUE, false);
ObjectWriter ow = mapper.writer().withDefaultPrettyPrinter();
String requestJson = ow.writeValueAsString(anObject);
System.out.println(requestJson);
MockHttpServletRequestBuilder builder = MockMvcRequestBuilders.post(url).contentType(MediaType.APPLICATION_JSON_UTF8).content(requestJson);
this.mockMvc.perform(builder).andExpect(ok).andDo(MockMvcResultHandlers.print());
}
}
My Test class using TestRestTemplate instead MockMvc returns 400
#RunWith(SpringJUnit4ClassRunner.class)
public class CreateEmailCommunicationDelegateTest {
#Before
public void setup() {
httpHeaders = new HttpHeaders();
// rest headers as above
}
#Test
public void testResponse() throws Exception, HttpClientErrorException, JsonProcessingException {
String url = "http://example.com/CommunicationDeliveryManagement-Service-1.0.0/communications/emails";
String username = "";
String password = "";
HttpEntity<CDMEmailRequest>
cDEntity = new HttpEntity<>(httpHeaders);
restTemplate = new TestRestTemplate(username, password);
responseEntity =
restTemplate.exchange(url, HttpMethod.POST, cDEntity,
CDResponse.class);
assertNotNull(responseEntity);
assertEquals(HttpStatus.OK,
responseEntity.getStatusCode());
}
}
I think you're trying to implement an integration test instead of an unit test, there is quite difference. MockMvc should be used to implement unit tests and TestRestTemplate for integration tests. You can't neither use it for testing a Client implementation.
See Unit and Integration Tests in Spring Boot
If you are working with Spring Boot you could achieve your goal using another approach see this question Spring boot testing of a rest client using #RestClientTest.

How to test Rest API endpoint which takes value from constantly changing external API

I use external API, which returns list of sorted by date Objects with many (approx. 30) properties.
I wrote simple Rest API using Spring Boot with one endpoint
/newest_obj_name
which just return currently newest name of Object from that list and ignore everything else.
How can I sufficiently test that code while the value from external API is constantly changing, so I cannot simply use String expected as in a code below?
Generally speaking how to approach whole testing issue in that scenario?
#RunWith(SpringRunner.class)
#SpringBootTest(classes = Application.class, webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
public class MyTest {
#LocalServerPort
private int port;
private TestRestTemplate restTemplate = new TestRestTemplate();
private HttpHeaders headers = new HttpHeaders();
#Test
public void testRetrieveNewest() {
HttpEntity<String> entity = new HttpEntity<String>(null, headers);
ResponseEntity<String> response = restTemplate.exchange(
createURLWithPort("/newest_obj_name"),
HttpMethod.GET, entity, String.class);
String expected = "{\"name\":\"crazy\"}";
try {
JSONAssert.assertEquals(expected, response.getBody(), false);
} catch (JSONException e) {
e.printStackTrace();
}
}
private String createURLWithPort(String uri) {
return "http://localhost:" + port + uri;
}
}

How to make a rest api call in java and map the response object?

I'm currently developing my first java program who'll make a call to a rest api(jira rest api, to be more especific).
So, if i go to my browser and type the url =
"http://my-jira-domain/rest/api/latest/search?jql=assignee=currentuser()&fields=worklog"
I get a response(json) with all the worklogs of the current user.
But my problem is, how i do my java program to do this ?
Like,connect to this url, get the response and store it in a object ?
I use spring, with someone know how to this with it.
Thx in advance guys.
Im adding, my code here:
RestTemplate restTemplate = new RestTemplate();
String url;
url = http://my-jira-domain/rest/api/latest/search/jql=assignee=currentuser()&fields=worklog
jiraResponse = restTemplate.getForObject(url,JiraWorklogResponse.class);
JiraWorkLogResponse is a simple class with some attributes only.
Edit,
My entire class:
#Controller
#RequestMapping("/jira/worklogs")
public class JiraWorkLog {
private static final Logger logger = Logger.getLogger(JiraWorkLog.class.getName() );
#RequestMapping(path = "/get", method = RequestMethod.GET, produces = "application/json")
public ResponseEntity getWorkLog() {
RestTemplate restTemplate = new RestTemplate();
String url;
JiraProperties jiraProperties = null;
url = "http://my-jira-domain/rest/api/latest/search?jql=assignee=currentuser()&fields=worklog";
ResponseEntity<JiraWorklogResponse> jiraResponse;
HttpHeaders httpHeaders = new HttpHeaders();
httpHeaders = this.createHeaders();
try {
jiraResponse = restTemplate.exchange(url, HttpMethod.GET, new HttpEntity<Object>(httpHeaders),JiraWorklogResponse.class);
}catch (Exception e){
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(e.getMessage());
}
return ResponseEntity.status(HttpStatus.OK).body(jiraResponse);
}
private HttpHeaders createHeaders(){
HttpHeaders headers = new HttpHeaders(){
{
set("Authorization", "Basic something");
}
};
return headers;
}
This code is returning :
org.springframework.http.converter.HttpMessageNotWritableException
Anyone knows why ?
All you need is http client. It could be for example RestTemplate (related to spring, easy client) or more advanced and a little more readable for me Retrofit (or your favorite client).
With this client you can execute requests like this to obtain JSON:
RestTemplate coolRestTemplate = new RestTemplate();
String url = "http://host/user/";
ResponseEntity<String> response
= restTemplate.getForEntity(userResourceUrl + "/userId", String.class);
Generally recommened way to map beetwen JSON and objects/collections in Java is Jackson/Gson libraries. Instead them for quickly check you can:
Define POJO object:
public class User implements Serializable {
private String name;
private String surname;
// standard getters and setters
}
Use getForObject() method of RestTemplate.
User user = restTemplate.getForObject(userResourceUrl + "/userId", User.class);
To get basic knowledge about working with RestTemplate and Jackson , I recommend you, really great articles from baeldung:
http://www.baeldung.com/rest-template
http://www.baeldung.com/jackson-object-mapper-tutorial
Since you are using Spring you can take a look at RestTemplate of spring-web project.
A simple rest call using the RestTemplate can be:
RestTemplate restTemplate = new RestTemplate();
String fooResourceUrl = "http://localhost:8080/spring-rest/foos";
ResponseEntity<String> response = restTemplate.getForEntity(fooResourceUrl + "/1", String.class);
assertThat(response.getStatusCode(), equalTo(HttpStatus.OK));
The issue could be because of the serialization. Define a proper Model with fields coming to the response. That should solve your problem.
May not be a better option for a newbie, but I felt spring-cloud-feign has helped me to keep the code clean.
Basically, you will be having an interface for invoking the JIRA api.
#FeignClient("http://my-jira-domain/")
public interface JiraClient {
#RequestMapping(value = "rest/api/latest/search?jql=assignee=currentuser()&fields=", method = GET)
JiraWorklogResponse search();
}
And in your controller, you just have to inject the JiraClient and invoke the method
jiraClient.search();
And it also provides easy way to pass the headers.
i'm back and with a solution (:
#Controller
#RequestMapping("/jira/worklogs")
public class JiraWorkLog {
private static final Logger logger = Logger.getLogger(JiraWorkLog.class.getName() );
#RequestMapping(path = "/get", method = RequestMethod.GET, produces = "application/json")
public ResponseEntity<JiraWorklogIssue> getWorkLog(#RequestParam(name = "username") String username) {
String theUrl = "http://my-jira-domain/rest/api/latest/search?jql=assignee="+username+"&fields=worklog";
RestTemplate restTemplate = new RestTemplate();
ResponseEntity<JiraWorklogIssue> response = null;
try {
HttpHeaders headers = createHttpHeaders();
HttpEntity<String> entity = new HttpEntity<>("parameters", headers);
response = restTemplate.exchange(theUrl, HttpMethod.GET, entity, JiraWorklogIssue.class);
System.out.println("Result - status ("+ response.getStatusCode() + ") has body: " + response.hasBody());
}
catch (Exception eek) {
System.out.println("** Exception: "+ eek.getMessage());
}
return response;
}
private HttpHeaders createHttpHeaders()
{
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_JSON);
headers.add("Authorization", "Basic encoded64 username:password");
return headers;
}
}
The code above works, but can someone explain to me these two lines ?
HttpEntity<String> entity = new HttpEntity<>("parameters", headers);
response = restTemplate.exchange(theUrl, HttpMethod.GET, entity, JiraWorklogIssue.class);
And, this is a good code ?
thx (:

Resttemplate getForEntity - Pass headers

Is it possible to set header as part of getForEntity method or should I use exchange? I am trying to set oauth header as part of getForEntity calls.
You can use .exchange:
ResponseEntity<YourResponseObj> entity = new TestRestTemplate().exchange(
"http://localhost:" + port + "/youruri", HttpMethod.GET, new HttpEntity<Object>(headers),
YourResponseObj.class);
Full Junit sample:
#RunWith(SpringRunner.class)
#SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT)
public class ReferenceTablesControllerTests {
#LocalServerPort
private int port;
#Test
public void getXxxx() throws Exception {
MultiValueMap<String, String> headers = new LinkedMultiValueMap<>();
headers.add("Content-Type", "application/json");
headers.add("Authorization", "tokenxxx");
ResponseEntity<YourResponseObj> entity = new TestRestTemplate().exchange(
"http://localhost:" + port + "/youruri", HttpMethod.GET, new HttpEntity<Object>(headers),
YourResponseObj.class);
Assert.assertEquals(HttpStatus.OK, entity.getStatusCode());
Assert.assertEquals("foo", entity.getBody().getFoo());
}
}

Basic authentication for REST API using spring restTemplate

I am completely new in RestTemplate and basically in the REST APIs also. I want to retrieve some data in my application via Jira REST API, but getting back 401 Unauthorised. Found and article on jira rest api documentation but don't really know how to rewrite this into java as the example uses the command line way with curl. I would appreciate any suggestion or advice how to rewrite:
curl -D- -X GET -H "Authorization: Basic ZnJlZDpmcmVk" -H "Content-Type: application/json" "http://kelpie9:8081/rest/api/2/issue/QA-31"
into java using spring rest template. Where the ZnJlZDpmcmVk is a base64 encoded string of username:password. Thank you very much.
Taken from the example on this site, I think this would be the most natural way of doing it, by filling in the header value and passing the header to the template.
This is to fill in the header Authorization:
String plainCreds = "willie:p#ssword";
byte[] plainCredsBytes = plainCreds.getBytes();
byte[] base64CredsBytes = Base64.encodeBase64(plainCredsBytes);
String base64Creds = new String(base64CredsBytes);
HttpHeaders headers = new HttpHeaders();
headers.add("Authorization", "Basic " + base64Creds);
And this is to pass the header to the REST template:
HttpEntity<String> request = new HttpEntity<String>(headers);
ResponseEntity<Account> response = restTemplate.exchange(url, HttpMethod.GET, request, Account.class);
Account account = response.getBody();
You may use spring-boot RestTemplateBuilder
#Bean
RestOperations rest(RestTemplateBuilder restTemplateBuilder) {
return restTemplateBuilder.basicAuthentication("user", "password").build();
}
See documentation
(before SB 2.1.0 it was #basicAuthorization)
There are multiple ways to add the basic HTTP authentication to the RestTemplate.
1. For a single request
try {
// request url
String url = "https://jsonplaceholder.typicode.com/posts";
// create auth credentials
String authStr = "username:password";
String base64Creds = Base64.getEncoder().encodeToString(authStr.getBytes());
// create headers
HttpHeaders headers = new HttpHeaders();
headers.add("Authorization", "Basic " + base64Creds);
// create request
HttpEntity request = new HttpEntity(headers);
// make a request
ResponseEntity<String> response = new RestTemplate().exchange(url, HttpMethod.GET, request, String.class);
// get JSON response
String json = response.getBody();
} catch (Exception ex) {
ex.printStackTrace();
}
If you are using Spring 5.1 or higher, it is no longer required to manually set the authorization header. Use headers.setBasicAuth() method instead:
// create headers
HttpHeaders headers = new HttpHeaders();
headers.setBasicAuth("username", "password");
2. For a group of requests
#Service
public class RestService {
private final RestTemplate restTemplate;
public RestService(RestTemplateBuilder restTemplateBuilder) {
this.restTemplate = restTemplateBuilder
.basicAuthentication("username", "password")
.build();
}
// use `restTemplate` instance here
}
3. For each and every request
#Bean
RestOperations restTemplateBuilder(RestTemplateBuilder restTemplateBuilder) {
return restTemplateBuilder.basicAuthentication("username", "password").build();
}
I hope it helps!
As of Spring 5.1 you can use HttpHeaders.setBasicAuth
Create Basic Authorization header:
String username = "willie";
String password = ":p#ssword";
HttpHeaders headers = new HttpHeaders();
headers.setBasicAuth(username, password);
...other headers goes here...
Pass the headers to the RestTemplate:
HttpEntity<String> request = new HttpEntity<String>(headers);
ResponseEntity<Account> response = restTemplate.exchange(url, HttpMethod.GET, request, Account.class);
Account account = response.getBody();
Documentation:
https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/http/HttpHeaders.html#setBasicAuth-java.lang.String-java.lang.String-
(maybe) the easiest way without importing spring-boot.
restTemplate.getInterceptors().add(new BasicAuthorizationInterceptor("user", "password"));
Reference Spring Boot's TestRestTemplate implementation as follows:
https://github.com/spring-projects/spring-boot/blob/v1.2.2.RELEASE/spring-boot/src/main/java/org/springframework/boot/test/TestRestTemplate.java
Especially, see the addAuthentication() method as follows:
private void addAuthentication(String username, String password) {
if (username == null) {
return;
}
List<ClientHttpRequestInterceptor> interceptors = Collections
.<ClientHttpRequestInterceptor> singletonList(new BasicAuthorizationInterceptor(
username, password));
setRequestFactory(new InterceptingClientHttpRequestFactory(getRequestFactory(),
interceptors));
}
Similarly, you can make your own RestTemplate easily
by inheritance like TestRestTemplate as follows:
https://github.com/izeye/samples-spring-boot-branches/blob/rest-and-actuator-with-security/src/main/java/samples/springboot/util/BasicAuthRestTemplate.java
Instead of instantiating as follows:
TestRestTemplate restTemplate = new TestRestTemplate();
Just do it like this:
TestRestTemplate restTemplate = new TestRestTemplate(user, password);
It works for me, I hope it helps!
HttpHeaders headers = new HttpHeaders();
headers.setBasicAuth(username, password);
then continue with the same procedure mentioned by the others here:
HttpEntity<String> request = new HttpEntity<String>(headers);
ResponseEntity<String> response = restTemplate.exchange(url, HttpMethod.GET,
request, String.class);
Use setBasicAuth to define credentials
HttpHeaders headers = new HttpHeaders();
headers.setBasicAuth("myUsername", myPassword);
Then create the request like you prefer.
Example:
HttpEntity<String> request = new HttpEntity<String>(headers);
ResponseEntity<String> response = restTemplate.exchange(url, HttpMethod.GET,
request, String.class);
String body = response.getBody();
I'm using spring version 5.3.15 for my unit test environment. I used withBasicAuth for my tests :
#SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
public class MyTestClass {
...
#Autowired
private TestRestTemplate restTemplate;
...
#Test
#SneakyThrows
public void TestGetSettings(){
DtoClass dtoClass = this.restTemplate
.withBasicAuth(UserServices.DEFAULT_USER, UserServices.DEFAULT_PASSWORD)
.getForObject(String.format("http://localhost:%d/setting",
port), DtoClass.class);
assertThat(dtoClass.getClientAddress()).isNotEmpty();
}
...
}
As you see this method only work for basic authentication. If you look at the details of the withBasicAuth method, you will find that the method source will be like this:
// TestRestTemplate.java file:
...
public class TestRestTemplate {
...
private final RestTemplateBuilder builder;
...
public TestRestTemplate withBasicAuth(String username, String password) {
TestRestTemplate template = new TestRestTemplate(this.builder, username, password, this.httpClientOptions);
...
}
}
As a result, for other types of authentication you can use the RestTemplateBuilder as a builder which is mentioned in other answers.
Follow Step By Step
I added Client Credentials In application.Properties file like below...
http.basicauth.username = yourUserName
http.basicauth.password = yourPassword
And , Then I created one class With two fields Because I'm loading those two fields from the Application.Properties file : username and password . Make sure your class is annotated with #Component..
#Value("${http.basicauth.username}")
private String username;
#Value("${http.basicauth.password}")
private String password;
And Then , You need to autowired above class From Wherever you want..
// I'm getting a username and password from application.properties file
String userCredentials = referenceClassName.getUsername()+":"+referenceClassName.getPassword();
// Encoded User Credentials and Convert it into a String
String encodedUserCredentials= Base64.getMimeEncoder().encodeToString(userCredentialsBytes.getBytes());
headers.set("Authorization", "Basic " +base64UserCredentials);
HttpEntity request = new HttpEntity(headers);
String url = "externalUrl";
// Getting a Json String body
String body = restTemplate.exchange(url,HttpMethod.GET,request,String.class).getBody();
Note :: For getting an Access Token from String Json body , That's why I converted it into a Json Object
JsonObject tokenJsonObject = new JsonParser().parse(body).getAsJsonObject();
// Getting access token as string from tokenJsonObject
String accessToken = tokenJsonObject.has("access_token") && !tokenJsonObject.get("access_token").isJsonNull() ? tokenJsonObject.get("access_token").getAsString() : "";
If you have any concerns, please let me know in comments..Hope It will helpful to you..
I have been using Spring above 5.1.x
// create headers for basic auth
var headers = new HttpHeaders();
headers.setBasicAuth("username", "password");

Categories