Testing a Jersey Client wrapper - java

I am trying to write a test for an API client that uses Jersey Client to make the requests.
I wanted to fake a certain server response to return a pre-captured json string.
Eg.
client().resource("/recommendations").queryParam("username", karan").get(Recommendation.class)
should return the appropriate class based on a json string I have stored in a file.
How can I fake that? Or would I have to instantiate a fake server to return the actual json, and let the jersey client to do it's work?
Thanks

One popular solution is to use a testing framework like EasyMock or Mockito to create a mock Jersey client which expects specific method calls and returns predefined data (e.g. json). The mock is then injected into the API client in place of the real Jersey client.
In general, you can also avoid the frameworks by creating the mock yourself, i.e. subclassing the client and overriding methods you expect to call, to return predefined data. Then pass your mock into the API client as a constructor argument. Whether or not you justify a framework depends on how much mocking you expect to need, which is determined in part by how many external dependencies you have.

Related

Spring Test Module vs Mockito

I am learning about integration testing a spring app that communicates with a rest API. I found out from this article that spring test supports two ways to do, what I assume the same thing.
Create a mockserver using MockRestServiceServer
Create a mock object using Mockito
I understand that the former intercepts http request; then returns the objects, while the latter returns the object directly without bothering with any http requests at all.
Since in the end, at least in most cases, we just verify the object retrieved and compare it to the expected result.
So, my Questions; if try to compare:
What are possible trade-offs; if I choose either one of them?
Are there any advantages of choosing one than the other?
For which cases would I prefer one compared to the other (possible
use cases of each)?
Mockito mocks out all internal part of restTemplate and just returns responses to method directly.
MockRestServiceServer lets restTemplate to run all the things before httpClient call.
It means you will test error handling, mapping etc with MockRestServiceServer.

Is it possible to make a real integration test with JerseyTest?

There are many pages on the net, declaring that they describe the creation of integration tests with JerseyTest. Such as:
https://blog.codecentric.de/en/2012/05/writing-lightweight-rest-integration-tests-with-the-jersey-test-framework/
But notice! It is not an integration test really. It mocks the whole service under the API function. So, it is a unit test. And all examples for 'integration' tests that I had found, are such mocking stubs.
And I want to create a really integration test, I want to send a JSON string and get back another JSON string (or HTML). Of course, for that Jersey in coordination with JerseyTest should collaborate somehow to create a request, call my API function, follow it to the DB queries, fulfil them, and return a response that I can assert by parts.
How can I do it? (If it is possible, of course)

Create the HttpServletRequest and HttpServletResponse message instead of mock

I am writing a unit test for filter to log request and response message. Can we create the HttpServletRequest and HttpServletResponse message instead of mock to send as a input to doFilter() method.
Sure, just implement the interface. However, these are large interfaces, so it's a lot of code to maintain instead of the mock.
If your reason to not use a mock is a simple aversion to mocks (good!) note that there's really no difference between manually implementing a "mock" object and letting a framework do it for you; in both cases you're giving your code something different from what the web framework you end up using will use.
The code you're writing is perhaps better tested with integration tests - starting a real web server as part of your test harness and generating real HTTP requests.
If you are trying to solve an issue the mocks are creating for you by manually implementing the interface, here's an example of a custom HttpServletRequest implemented as an extension of the implementation that ships with Jetty:
https://github.com/neo4j/neo4j/blob/3.2/community/server/src/main/java/org/neo4j/server/rest/web/InternalJettyServletRequest.java

Java's Jersey, RESTful API, and JSONP

This must have been answered previously, but my Google powers are off today and I have been struggling with this for a bit. We are migrating from an old PHP base to a Jersey-based JVM stack, which will ultimately provide a JSON-based RESTful API that can be consumed from many applications. Things have been really good so far and we love the easy POJO-to-JSON conversion. However, we are dealing with difficulties in Cross-Domain JSON requests. We essentially have all of our responses returning JSON (using #Produces("application/json") and the com.sun.jersey.api.json.POJOMappingFeature set to true) but for JSONP support we need to change our methods to return an instance of JSONWithPadding. This of course also requires us to add a #QueryParam("callback") parameter to each method, which will essentially duplicate our efforts, causing two methods to be needed to respond with the same data depending on whether or not there is a callback parameter in the request. Obviously, this is not what we want.
So we essentially have tried a couple different options. Being relatively new to Jersey, I am sure this problem has been solved. I read from a few places that I could write a request filter or I could extend the JSON Provider. My ideal solution is to have no impact on our data or logic layers and instead have some code that says "if there is a call back parameter, surround the JSON with the callback, otherwise just return the JSON". A solution was found here:
http://jersey.576304.n2.nabble.com/JsonP-without-using-JSONWithPadding-td7015082.html
However, that solution extends the Jackson JSON object, not the default JSON provider.
What are the best practices? If I am on the right track, what is class for the default JSON filter that I can extend? Is there any additional configuration needed? Am I completely off track?
If all your resource methods return JSONWithPadding object, then Jersey automatically figures out if it should return JSON (i.e. just the object wrapped by it) or the callback as well based on the requested media type - i.e. if the media type requested by the client is any of application/javascript, application/x-javascript, text/ecmascript, application/ecmascript or text/jscript, then Jersey returns the object wrapped by the callback. If the requested media type is application/json, Jersey returns the JSON object (i.e. does not wrap it with the callback). So, one way to make this work is to make your resource method produce all the above media types (including application/json), always return JSONWithPadding and let Jersey figure out what to do.
If this does not work for you, let us know why it does not cover your use case (at users at jersey.java.net). Anyway, in that case you can use ContainerRequest/ResponseFilters. In the request filter you can modify the request headers any way you want (e.g. adjust the accept header) to ensure it matches the right resource method. Then in the response filter you can wrap the response entity using the JSONWithPadding depending on whether the callback query param is available and adjust the content type header.
So what I ultimately ended up doing (before Martin's great response came in) was creating a Filter and a ResponseWrapper that intercepted the output. The basis for the code is at http://docs.oracle.com/cd/B31017_01/web.1013/b28959/filters.htm
Essentially, the filter checks to see if the callback parameter exists. If it does, it prepends the callback to the outputted JSON and appends the ) at the end. This works great for us in our testing, although it has not been hardened yet. While I would have loved for Jersey to be able to handle it automatically, I could not get it to work with jQuery correctly (probably something on my side, not a problem with Jersey). We have pre-existing jQuery calls and we are changing the URLs to look at the new Jersey Server and we really didn't want to go into each $.ajax call to change any headers or content types in the calls if we didn't have to.
Aside from the small issue, Jersey has been great to work with!

Best way to model system with a single interface used in different ways in java

I have a class that implements an interface
class TopLevel implements TopLevelOperations
inside TopLevel the operations are implemented in 2 different ways. So some of the operations in TopLevelOperations need to be called as SOAP client calls and some as restful calls.
What would be the best way to model this? Create additional two interfaces SOAPOperations and RESTOperations to specify what is the responsibility of restful and SOAP respectively ? Then use two other classes internally that implement those interfaces? The motivation is that I may one day want to swap out SOAP for some other approach.
Better way?
Edit: I also don't want different client code jumbled together in TopLevel as it currently is.
What you need to do is separate the transport layer from the payload.
Both requests over the network are over HTTP but the payload is different, i.e. it is wrapped in a SOAP envelope in one case and pure xml data in REST.
So for the higher lever code you should have an interface that just sends a message, encapsulated in an object.
The implementation of this interface converts the message to XML (via DOM or JAXB etc).
Then this XML is passed to a transport layer to be send over HTTP or wrapped in a SOAP message before passing it to the transport layer.
The transport layer can be just a concrete class that is as simple as:
public class HttpClient{
public String sendMsg(String xml){
//Use some HTTP client to send message and return the response.
//The input could be SOAP or plain xml app data
//The output could be SOAP or plain xml app data
}
}
So the user configures your objects to use SOAP or not.
The application code is only aware of the interface to send message.
In your implementation, because of the separation of XML transformation and HTTP transport layers you can swap implementations or add new ones.
Not sure the solution needs to be that complex (assuming I understand the problem of course...):
Make sure TopLevelOperations declares all the methods a client can use. Do so in a protocol-independent way, e.g. TopLevelOperations.doFoo(), not TopLevelOperations.doFooOverSOAP()
Implement TopLevel as your first version of the interface using SOAP/REST as appropriate.
Ensure clients only ever reference TopLevelOperations when declaring references - never the implementing class
Use whatever mechanism is appropriate for your app to inject the appropriate implementation into the clients (Dependency Injection / Factory / ...).
If / when you want to re-implement the methods using a different transport/protocol just create another class (TopLevelNew) that implements TopLevelOperations. Then inject it into clients instead of TopLevel in step 4 above.
Deciding which implementation to use is then an application-level configuration decision, not something the clients have to be aware of.
hth.
[You may also want/need to use some helpers classes for the implementation, e.g. separating content from payload as per #user384706's answer. But that's complementary to above (i.e. how to design the implementation vs. how to keep interface consistent for clients).]

Categories

Resources