I've written a monitoring service class performing a database check for entries of a certain (considered erroneous) state. Based on the result of the database query, the service will send a notification to a Microsoft Teams channel using its Connector/Webhook functionality. It works all fine so far, but I can't wrap my head around how to properly test the respective methods. It's mainly the method sending the notification to Teams I'm struggling with:
public HttpStatus sendNotificationToTeams(MsTeamsCard card) throws JsonProcessingException {
HttpHeaders headers = new HttpHeaders();
ObjectWriter writer = new ObjectMapper().writer();
Proxy proxy = new Proxy(Proxy.Type.HTTP, new InetSocketAddress(WebConfig.PROXY_HOST, WebConfig.PROXY_PORT));
SimpleClientHttpRequestFactory requestFactory = new SimpleClientHttpRequestFactory();
// Setup RestTemplate. Proxy is required, otherwise request returns HTTP 500 with misleading error message (array index out of bounds)
requestFactory.setProxy(proxy);
RestTemplate restTemplate = new RestTemplate(requestFactory);
// HTTP request incl. setup
headers.setContentType(MediaType.APPLICATION_JSON);
HttpEntity<String> request = new HttpEntity<>(writer.writeValueAsString(card), headers);
ResponseEntity<String> response = restTemplate.exchange(this.webhookUrl, HttpMethod.POST, request, String.class);
return response.getStatusCode();
}
I think I should definitely test this method since it's not trivial at all. However, there's not much that I think could reasonalby fail inside this method that is related to its particular arrangement of code - of course there may be problems, but things like network issues are out of scope of (unit) tests for this method. So how would I test this method reliably? I'm asking more from a general testing point of view (which is where I really lack knowledge) than requesting concrete help with a test framework or something (JUnit 4 is used btw). For example, one point is that I can't check the results of the HTTP call even if I mock it, because it requires a specific answer from Teams: the request might be successful but something could be wrong with Teams, and I can't really mock that. But maybe I'm just thinking too complicated here.
If you are looking for unit-testing your http-connector, you can do it with Wiremock. Check out this tutorial
For instance
#Test
public void shouldSendNotification() {
String path = "/endpoint";
wiremock.stubFor(get(urlEqualTo(path))
.willReturn(aResponse()
.withStatus(200))
);
HttpStatus status = sendNotificationToTeams(...);
assertThat(status).isEqualTo(200);
}
Related
I am using Spring 4.3 and SpringBoot 1.5 to create a component that has to call an external REST service. This external service requests HTTP Basic Authentication.
I found that SpringBoot provides a very useful builder to set up RestTemplate properties, such as basic authentication, RestTemplateBuilder.
To call the external REST service I have to use the method RestTemplate.exchange, because of the List<T> return type.
new RestTemplateBuilder().basicAuthorization(username, password)
.build()
.exchange("/some/path/with/variables",
HttpMethod.GET,
new HttpEntity<>(new HttpHeaders()),
new ParameterizedTypeReference<List<Integer>>() {},
some, params)
The problem here is that the signature of the exchange method requests an object of type HttpEntity, that is basically a container of HttpHeaders.
The question is, will the HttpEntity object, passed as input parameter to the exchange method, subscribe the Basic Auth header set using the RestTemplateBuilder.basicAuthorization method?
Thanks a lot.
I have done some experiments during the past couple of days. The instance of HttpEntity passed to the exchange method does not subscribe the information relative to the Basic Authentication set by the RestTemplateBuilder. The two sets of headers are merged into one.
Nice shot, Spring ;)
//1) Request
//Given
String req = new ObjectMapper().writeValueAsString(new Request("2016-11-15"));
//set HttpHeaders
//set HttpEntity
// When
ResponseEntity responseEntity = restTemplate.exchange(url, HttpMethod.POST, httpEntity, String.class);
Is there a convenient way of unit testing multiple REST API requests? I would like to create a bunch of requests to submit to a queue which will then be processed. The request are to have different HttpHeaders and different ReportRequestBody.
I have done single request unit testing and are able to capture statuses using ResponseEntity.
Can anyone point me to some examples or documentation on best practices. I am a beginner and I am not sure where to start with multiple requests.
For testing requests and responses in DjangoRest you can use following tools or ways....
You can use print statement to see what is being printed and then you can interpret print results accordingly.
You can use Debugger of any IDE such as PyCharm.
You can use Postman to test your API as it gives you whole idea of
the responses you are getting.
For more information on requests you can visit here
Yes I would certainly say this is more of an integration/load test scenario. You may want to look into using Jmeter with Junit tests. You can use its JUnit Request Sampler. Here was a post on stackoverflow to a different question, but it provides a link to a helpful article. The post was Spring load testing . Here is also a link to the article directly https://www.blazemeter.com/blog/how-use-junit-jmeter. This should get you heading in the right direction.
I am implementing a Spring client for an existing REST API and I need to invoke a DELETE while, at the same time, passing an access token in the request body, like this:
{
"access_token": "..."
}
The problem is that, using the method that works for POST, the transmitted body is empty (I have intercepted the request body and made sure) and I cannot be authorised without this access token. This is what I am doing:
RestTemplate restTemplate = new RestTemplate();
UserRequest ur = new UserRequest(access_token);
HttpEntity<UserRequest> entity = new HttpEntity<>(ur);
restTemplate.delete(url, entity);
I have no control over the API itself, so I don't have the option of passing the token as url parameter.
Is there a way to do this in Spring, or do I have to build my own HttpUrlConnection like described for instance in this SO answer?
In the RestTemplate object in Spring there's an exchange method.
The parameters are :
the url
the method, in your case HttpMethod.DELETE
the entity (with the body you have to transmit)
the response type
some object you could pass
Hope this help
I'm trying to get access to the HTTP headers that are injected by Rest Assured. Spring's Mock MVC gives you access to pretty much everything via the MvcResult, and you can use this result to log pretty much anything you would like about the request and response. The only way I can see how to do this is in RestAssured is with a Filter. However, it gives you limited access to the request (you just get the RequestSpecification). I understand that it might be tricky to get access to headers that are added by the HttpClient, but it doesn't look like you can even get access to headers that are added by Rest Assured itself. For example, I can't see any OAuth related headers, nor content-type or content-length. The only headers that appear are those that were manually added using, for example, .contentType(ContentType.XML)
Is there any other way to get access to those headers? I don't need to modify the request, I just want to be able to log all of it and the headers that are injected by Rest Assured.
I found that it's possible to register your own HttpClientFactory with RestAssured:
RestAssured.config().httpClient(
HttpClientConfig.httpClientConfig().httpClientFactory(
new CustomHttpClientFactory())
So I created a new factory that returns an HTTP client into which I inject some request and response interceptors.
public class CustomHttpClientFactory extends HttpClientConfig.HttpClientFactory {
#Override
public HttpClient createHttpClient() {
DefaultHttpClient client = new DefaultHttpClient();
client.addRequestInterceptor((request, ctx) -> {
// do what you will
});
client.addResponseInterceptor((response, ctx) -> {
// do what you will
});
return client;
}
}
This gives you almost full access to manipulate the request and response. One thing to remember is that if you're going to read from the response's entity, you should first wrap it in a BufferedHttpEntity to make it re-readable:
if (response.getEntity() != null && !response.getEntity().isRepeatable()) {
response.setEntity(new BufferedHttpEntity(response.getEntity()));
}
Another problem I ran into is when trying to see the OAuth related information. When using RestAssured's OAuth functionality, it adds its own OAuthSigner interceptor to the HTTP client right before executing the request. This means that it will always be the last interceptor to be called and any interceptor you may have already injected will be called before the request ever gets signed. Because I don't really need to see the signature for now, I didn't investigate this further and I'm leaving it as an exercise for the reader. ;)
I looked for the similar question but could not find any . I have a micro service created with drop-wizard which is running in localhost:9000.
I am working in another project(with spring mvc) running in 8080. I wan to call the above service which gives me string back from any of my controllers in main project .lets say the path is "localhost:9000/giveMeString" .
You can use Apache's HTTP Client. See this example borrowed from their documentation:
// Create an instance of HttpClient.
HttpClient client = new HttpClient();
// Create a method instance.
GetMethod method = new GetMethod("http://localhost:9000/giveMeString");
// Execute the method.
int statusCode = client.executeMethod(method);
// Read the response body.
byte[] responseBody = method.getResponseBody();
//Print the response
System.out.println(new String(responseBody));
If you're really going down the microservice path, note that creating an HTTP client for every request and making synchronous, blocking requests won't really scale.
Here are a few ideas, if you're using Spring:
Create a single RestTemplate instance
You can create a single RestTemplate instance and inject it in multiple places in your application.
#Configuration
public class MyConfiguration {
#Bean
public RestTemplate restTemplate() {
return new RestTemplate(new HttpComponentsClientHttpRequestFactory());
}
}
Better, wrap that REST client with a Cache
Check out Sagan's take on this.
Even better, go asynchronous
You can use an AsyncRestTemplate; very useful, especially if your Controllers need to make multiple requests and if you don't want to block your webapp thread. Your Controller can even return a DeferredResult or a ListenableFuture, which will make your webapp more scalable.
And Spring Cloud + Netflix
You can also check Spring Cloud and Spring Cloud Netflix.
You'll see there interesting features: load-balancing, recovery, circuit breakers, etc.