Passing an HTTP call inside a test context - java

I am trying to unit test a Spring bean I implemented, but come across a difficulty here. This bean is to call a distant REST service on certain occasions.
However, in my tests, I would like it to call a mock servlet inside my test context, not a distant server.
The call is made using Apache's httpclient library, the URL is set in the applicationContext (so I can provide any fake URI to the bean when testing). The service should return a stream.
The call looks like the following:
HttpClient client = new DefaultHttpClient();
URIBuilder builder = new URIBuilder(theURIProvidedInContext);
// set parameters on builder
URI uri = builder.build();
HttpGet get = new HttpGet(uri);
HttpEntity entity = client.execute(get).getEntity();
return entity.getContent();
I searched Google all morning but only found how to unit-test servlets. Can anybody give some insight here?

You're not going to be able to call a mock servlet in a test context because there's no application server. Instead, you can pull out that code that uses HTTP Client to make the call into a separate bean, and then mock that to return the desired stream.
If it's a REST service, you can create a JAX-RS annotated class as a test double (I won't call it a mock), and start it with an embedded server like Grizzly or Jersey. That will start up an HTTP server for you. Your annotated class can throw 404, 500, etc. depending on how you want the test to proceed. See JAX-RS with embedded server

Try com.rexsl.test.ContainerMocker from com.rexsl:rexsl-test:mock:0.3.8 (I'm a developer):
URI home = new ContainerMocker()
.expectMethod("GET")
.expectHeader("Accept", Matchers.startsWith("text/"))
.returnBody("<done/>")
.returnStatus(200)
.mock()
.home();
Now you have a URI with a running HTTP container, which you can inject it into your classes.

Related

How to configure and build a custom RestTemplate for each client in Spring?

I am using Spring RestTemplate for executing HTTP request from my application. There are several services we need to call, some on the internet and some on intranet, some fast and some slow. I have been instructed to configure custom settings for each service, basically, connection timeout, read timeout.
These setting will be extremely specific for example, the services hosted on intranet would have a timeout of ~2-5s while they provide an SLA of 1000ms for 99.9% of requests. While the other third party services with ~10-60s.
As these parameters can be set in the factory for the template only, i am creating a number of beans with different factories differing in timeouts only. Something like this:
#Bean
RestTemplate restTemplate() {
HttpComponentsClientHttpRequestFactory factory = new HttpComponentsClientHttpRequestFactory(httpClient);
factory.setReadTimeout(20000);
factory.setConnectTimeout(5000);
RestTemplate restTemplate = new RestTemplate(factory);
}
I am afraid this will create a maintenance nightmare eventually. Can it be solved in a better ways?
PS: The application is a monolith calling various services.
You will have to create multiple RestTemplates and assign timeouts, connection pool size. Connection pool will improve the performance drastically
I have hard-coded the connection properties, you can pick it from application.properties file
#Configuration
class RestTemplateConfigs {
#Bean
public HttpClient httpClient() {
return HttpClientBuilder.create()
.setMaxConnPerRoute(200)
.setMaxConnTotal(50)
.setConnectionTimeToLive(10L, TimeUnit.SECONDS)
.build();
}
#Bean(name = "restTemplate1")
RestTemplate restTemplate() {
HttpComponentsClientHttpRequestFactory factory = new HttpComponentsClientHttpRequestFactory(httpClient());
RestTemplate restTemplate = new RestTemplate(factory);
return restTemplate;
}
}
You can create multiple RestTemplates and Autowire it using Qualifier name.
Disclaimer: my answer suggests to work with another Http client than Rest Template - If you must use Rest template my answer would be irrelevant.
I dealt with a similar design issue and here is what I did. I wrote my own HttpClient class. It is much simpler in use then most known Http clients. This class could be used on its own or (and this is relevant for your case) it could be used as a parent class for a group of classes (implementing the same interface) where each class will be an Http client for specific Rest Service. On this class you can pre-set the target URL and all the parameters (such as read and connection timeouts etc). Once this class is preset, all you need to do is to invoke sendHttpRequestMethod(). Just to expand a bit - lets say you have a User Rest service with CRUD API implemented by particular URL calls with different HTTP methods and may be different URLs. (say in addition to create (POST) update (PUT) read (GET) and delete (DELETE) methods that are located at HTTP://www.myserver.com:8083/user say you will also have methods activate and deactivate (say both GET) at URLs HTTP://www.myserver.com:8083/user/activate/ and HTTP://www.myserver.com:8083/user/deactivate.
So, in this case, your Http client will set all required timeouts and other configurations and it will also have pre-set target URL HTTP://www.myserver.com:8083/user. and it will have six methods as mentioned above, where each one will simply invoke the parent class method sendHttpRequest(). Of course, for activate and deactivate methods you will need to append "activate" and "deactivate" suffixes for pre-set base URL. So, for each REST service, you can create a dedicated Http client with very minimal effort since the base class already does most of the job. In addition to it, I wrote a self-populating factory for any group of classes that implement the same interface. With that factory, all you will have to do is to write your additional Http client and the factory will detect it and will make it available on its own by predefined name or by the name of the class (based on your choice). All this worked so well for me, that I packaged it into Open Source library called MgntUtils and published it on Maven and Github (with source code and Javadoc. JavaDoc is available here). A detailed explanation on the Self-populating factory can be seen in Javadoc here. Also, the general article about the library can be found here and specific article about the idea and the implementation of self-populating Factory can be found here. Package com.mgnt.lifecycle.management.example in the source code contains a working example. I hope this helps.
Using parameterized construction of the RestTemplate bean solved my problem.
The bean is now configured as:
#Bean
#Scope(BeanDefinition.SCOPE_PROTOTYPE)
public RestTemplate getRestTemplate(String configParam){
int connectionTimeout; //get from config using configParam
int readTimeout; //get from config using configParam
HttpComponentsClientHttpRequestFactory factory = new HttpComponentsClientHttpRequestFactory();
factory.setConnectTimeout(connectionTimeout);
factory.setReadTimeout(readTimeout);
return new RestTemplate(factory);
}
Instead of #Autowiring this field, it can be injected in may be #PostConstruct method like depicted below. The dependent bean can do following:
#Autowire
BeanFactory beanFactory;
RestTemplate restTemplate;
#PostConstruct
public void init(){
restTemplate = beanFactory.getBean(RestTemplate.class, configParam);
}
Here you can have your bean with custom settings injected in restTemplate.

Jersey client testing

I have a Jersey client which performs post request to some black box service.
Also I have POJO mapping feature enabled.
I have integration tests already, they are calling real black box service.
Now I need to test my application without calling real black box service.
My question is: how can I test this Jersey client? I mean: how can I test Jersey client without calling real black box service?Maybe there is some possibility to mock JSON response in tests?
Environment: jersey-client and jersey-json versions - 1.19.1.
You can log the request using LoggingFilter to make sure your requests are according to your estimate. For running your test, you can use http://mockable.io/.
P.S. Do not forget to replace the Webtarget URL with MockableIO's URL.
You can try Karate which has recently introduced a way to create simple mocks for JSON responses. Here is an example:
https://gist.github.com/ptrthomas/35ef9d40623cbeade7388b2cbb29a3b1
While the above example is a "smart" mock, it is very easy to create hard-coded mocks, here is an example: https://github.com/intuit/karate/blob/master/karate-netty/src/test/java/com/intuit/karate/mock/_mock.feature
You can easily read files from JSON by using the read keyword.
I have performed an investigation concerning my question. Mentioned investigation resulted in such facts:
I haven't found features/mechanisms/etc. to test Jersey client without real calls to the server (in my case - black box service).
Jersey test framework provides features for testing Jersey server, but there are no features for testing Jersey client
The only one solution for testing client without server is to refactor my code in following way: split logic into two phazes. First phaze: get JSON response using Jersey. Second phaze: get JSON response (which we get in first phaze) and transform it into desired object. In general you'll have next code as a result:
Class< String > jsonResposeClass = String.class;
String jsonResponse = post( yourRequest, jsonResposeClass );
ObjectMapper mapper = new ObjectMapper();
YourResponseBean bean = mapper.readValue( jsonResponse , responseClass );
The solution above will give you a possibility to use mocking libraries like Mockito and mock method which performs post request.
If you have found any other solution/feature/special mechanism/etc which can also help in such kind of situation - please share :)

Calling a micro service

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.

Jersey client creation in a REST service

i am creating a http REST service that consumes other http REST services.
I am using Jersey Client to call other services and i have many doubt about which creation pattern of the http client is the best.
Currently i am using EJB with injection of the client that is a Singleton shared by every methods, but i would like to remove java ee dependency and use Jetty as embedded application server.
I see from the doc that Client creation is an expensive operation so i cannot create one every time i need it.
I think about creating 1 in the constructor of every Servlet/Rest class is the simpler solution but i am not sure about the lifecycle of the servlet (if an instance is created for every request, this method is quite the same as the previous)
Or maybe is better to create a Singleton shared by every Servlet/Rest class
Or maybe better a pool of N client.
About this last two solution i need some advice... What do you think it's the better solution?
Thanks
According to you, there is a REST Service deployed in some environment and there is one application, a client or consumer, which wants to access that service.
If i am writing a normal Java class as client using Jersey API, then i will write something lime this :
import com.sun.jersey.api.client.Client;
import com.sun.jersey.api.client.ClientResponse;
import com.sun.jersey.api.client.WebResource;
Client client = Client.create();
WebResource webResource = client
.resource("http://localhost:8080/rest/example/employees");
ClientResponse response = webResource.accept("application/json")
.get(ClientResponse.class);
String result = response.getEntity(String.class);
Now say you are writing a servlet, which does some defined job in you application, also it makes a call to the REST Service using client block of code, everytime you access the servlet it will create a instance of com.sun.jersey.api.client.Client each time.
If you want to avoid this then you can create a initial class that will create an instance of com.sun.jersey.api.client.Client, one and only, and make it static and use the same reference where ever you want. WebResource should be created as and when required, because you might be interested to call different URIs.
I would have followed this approach, if i were in your situation.

Servlet Testing

I am using the ServletTester class provided by Jetty to test one of my servlets.
The servlet reads the the body of the request using InputStream.read() to construct a byte[] which is the decoded and acted on by the servlet.
The ServletTest class provides a method getResponses(ByteArrayBuffer) but I'm unsure how to create one of these in the correct format since it would also need to contain things like headers (e.g. "Content-Type: application/octet-stream).
Can anyone show me an easy way to construct this, preferably using an existing library so that I can use it in a similar way to the HttpTester class.
If there is a "better" way to test servlets (ideally using a local connector rather than via the tcp stack) I'd like to hear that also.
Many thanks,
Why use a mock at all? Why not test the servlet by running it in jetty?
Servlet servlet = new MyServlet();
String mapping = "/foo";
Server server = new Server(0);
Context servletContext = new Context(server, contextPath, Context.SESSIONS);
servletContext.addServlet(new ServletHolder(servlet), mapping);
server.start();
URL url = new URL("http", "localhost", server.getConnectors()[0].getLocalPort(), "/foo?bar");
//get the url...assert what you want
//finally server.stop();
Edit: Just wanting to reassure people that this is very fast. Its also a very reliable indicator of what your code will actually do, because it is in fact doing it.
Spring MVC provides a small set of "mock" classes for the various javax.servlet interfaces, such as HttpServletRequest, HttpSession, and so on. This makes it easy to unit test the likes of a servlet, you just inject mocks into the e.g. doGet() method.
Even if you don't use Spring itself on the server, you can still use the mock from the library, just for your tests.
You can use HttpClient to simplify testing somewhat. Take a look at the following article:
http://roberthanson.blogspot.com/2007/12/testing-servlets-with-junit.html
That in combination with servlet tester should give you what you want unit test wise.

Categories