How to mock a HTTP response - java

I'm a newbie to Java Unit test. The issue I'm facing is that I need to develop a JUnit test to send requests to a server'API to test two methods: addUser and deleteUser. If I want to add/delete a user from the server, I need to get an authentication token from the server; However, due to some issue on the server side, I currently can't get a valid token. So what comes to my mind, is to mock the server's behavior that if the server receives requests from the Unit test, it could response with a JSON data which indicates the status of the add/delete-user operations.
Because I'm totally new to JUnit. I have no clue how to implement the operation. So my question is what is probably the easiest way to apply the mock?

HttpResponse httpResponse = mock(HttpResponse.class);
see this: Mocking Apache HTTPClient using Mockito

You can start a test-http-server in your unit-test.
There are several frameworks to do it. For example Mockserver and Wiremock.

You can do it by using the HTTP Unit Testing from Google.
In order to generate a simple HTTP response you can use this code :
HttpTransport transport = new MockHttpTransport();
HttpRequest request = transport.createRequestFactory().buildGetRequest(HttpTesting.SIMPLE_GENERIC_URL);
HttpResponse response = request.execute();
You can also customize your testing by overriding the implementation of the MockHttpTransport class.
You can check here the repo of this for more details. I think it can be suitable for you.

Related

How to proxy (almost) all requests through WireMock?

I have a following problem: There's a service I'm mocking (for integration tests) using a docker container I run on a specific port. Because the mock service has not been updated (I don't own the code) a few endpoints that exist in the real service are not supported there.
I'm considering forking the repository and adding them myself, but other solution I'm trying is proxying all the requests via a WireMock server and stubbing only the missing endpoints. Is there a simple way to achieve this? It looks like I'd need to proxy every rest method separately, like this:
WireMockServer wireMockServer = new WireMockServer(8080);
wireMockServer.start();
// Proxy to the standalone mock server:
// GET
wireMockServer.stubFor(get(anyUrl())
.atPriority(10)
.willReturn(aResponse().proxiedFrom("http://localhost:8081/the-standalone-service")));
// POST
wireMockServer.stubFor(get(anyUrl())
.atPriority(10)
.willReturn(aResponse().proxiedFrom("http://localhost:8081/the-standalone-service")));
// PUT
wireMockServer.stubFor(put(anyUrl())
.atPriority(10)
.willReturn(aResponse().proxiedFrom("http://localhost:8081/the-standalone-service")));
...
// Overwrite only selected endpoints:
wireMockServer.stubFor(get(urlEqualTo("/the-service/users/"))
.atPriority(1)
.willReturn(aResponse()
.withHeader("Content-Type", "application/json")
.withBody("...")));
...
It took me less time to find an answer than writing the question, there's a WireMock.any() method matching all request methods, so this should suffice:
// Proxy to the standalone mock server:
wireMockServer.stubFor(WireMock.any(anyUrl())
.atPriority(10)
.willReturn(aResponse().proxiedFrom("http://localhost:8081/the-standalone-service")));
I'll confirm if it works later today.

How to mock response of an external API called from within an internal API integration test

I am writing integration tests for an application that uses an internal REST API to perform an action; all Java.
In the API, there is a POST method that calls upon an external API. In the test, I need to send a request to my API to perform an action.
The problem is, I do not want to send real requests to the external API when running the integration tests.
How can I mock the response of the external API call?
Is there a way I can still send a POST request to my API (mocked or otherwise) within my test, but use a mocked response for the external call performed in the Java POST method?
I've done this as follows: create a service layer that makes the API calls to external services. I built mine on Spring's RestTemplate but you could use whatever library to make calls. So it'll have methods like get() or post().
Then I use Postman to perform some requests against the external API and save the responses in files and add these files to my project.
Finally, in my tests, I mock out the calls to my little API service layer so that instead of going to the external API, it reads from the test files I saved previously. This runs the code under test with known payloads that came from the external API, but without requiring a connection to it during the test, and which won't change until I update the responses in the files myself.
I use EasyMock but any mocking library will work. Here's an example of what a test looks like.
#Test
public void test_addPhoneToExternalService() {
// Mock my real API service.
ApiService mockApiService = EasyMock.createMock(ApiService.class);
// Construct my service under test using my mock instead of the real one.
ServiceUnderTest serviceUnderTest = new ServiceUnderTest(mockApiService);
// Expect the body of the POST request to look like this.
Map<String, Object> requestBody = new HashMap<String, Object>() {{
put("lists", 0);
put("phone", "800-555-1212");
put("firstName", "firstName");
put("lastName", "lastName");
}};
// Read the response that I manually saved as json.
JsonNode expectedResponse = Utils.readJson("response.json");
expect(mockApiService.post(anyObject(),
eq("https://rest.someservice.com/api/contacts"), eq(serialize(requestBody))))
.andReturn(expectedResponse);
EasyMock.replay(mockApiService);
// Call the code under test. It ingests the response
// provided by the API service, which is now mocked,
// and performs some operations, then returns a value
// based on what the response contained (for example,
// "{\"id\":42}").
long id = serviceUnderTest.addPhone("firstName", "lastName", "800-555-1212");
Assert.assertThat(id, is(42L));
EasyMock.verify(mockApiService);
}
Hope that helps!

Jersey client get sent data to String

I am building some JUnit tests for a REST client using Jersey, I therefore need to have a copy of the data sent to the server to run some tests in JUnit.
Currently my clients invokes:
Invocation invocation = serviceWebTarget.request(MediaType.APPLICATION_JSON).
buildPut(Entity.json((QARecord) valuesList.get(0)));
Response response = invocation.invoke();
In between the two calls the QARecord object is serialized to JSON and sent to the server but I cannot find a way to access it.
By debugging the code I found no variable in either invocation or response which contains the converted JSON text.
How can get the sent data into a String or a File for my JUnit test to check what has been sent?
As i understood you want to check what exactly client will sent to server as a request, am i right ?
If yes how exactly does your Unit test look like ?
For instance Jersey provides JerseyTest class which is base for testing of client code.
In few words such test will run special testcontainer which is able to execute your handlers inside.
By combining it with Mockito / or creating your own handlers by yourself, you can verify what is "captured" by them as a client request at the end of the test (when response is received by client). Among others it'll give you possibility to check not only what your client code is sending to server but also check behaviour of client by emulating various responses (successful or exceptional).
If you just want to get content of what client is really send to the server you can write jersey client filter and get body of request from there.
Filters and Interceptors

Using wiremock, can I return a body that is dependent on the post request

I am trying to test an openid provider class. The openid consumer class is making an http request. I am mocking the response to this request using wiremock. I am trying to mock a valid openid response. However, the valid response depends on the request parameters. Using wiremock, can I set up a mock request where the body of the response is dependent on the request parameters?
This is possible, you just have to make use of a ResponseTansformer. In the below example code the responseDefinition is determined by the stubbing given below. Here I mock an encoding service by simply returning the body bytes back to the caller. Although in the transformer I am free to return whatever I like based on the contents of the request.
int port = 8080;
WireMockServer wireMockServer = new WireMockServer(new WireMockConfiguration().port(port).extensions(new ResponseTransformer() {
#Override
public ResponseDefinition transform(Request request, ResponseDefinition responseDefinition, FileSource files) {
return new ResponseDefinitionBuilder().like(responseDefinition)
.withBody(request.getBodyAsString().getBytes())
.build();
}
#Override
public String name() {
return "request body returning request transformer";
}
}));
wireMockServer.start();
WireMock.configureFor("localhost", port);
stubFor(post(urlEqualTo("/encode"))
.willReturn(aResponse()
.withHeader("Content-Type", "application/octet-stream")
.withStatus(200)));
stubFor(post(urlEqualTo("/decode"))
.willReturn(aResponse()
.withHeader("Content-Type", "application/octet-stream")
.withStatus(200)));
Wiremock supports extensions that you can write yourself that act as a middleware used to intercept the request and response bodies so you can format it however you like. It's very flexible and allows you to make up new response bodies dynamically or even no response at all.
As an example, we wrote an extension for this at Opentable and open sourced it on Maven Central. It allows you treat the json attributes as variables and interpolate them into your response body. Check it out. Let us know how it goes or if you have any questions.
https://github.com/opentable/wiremock-body-transformer
As far as I know and my experience with WireMock, no.
You can't parameterize a response with arguments passed through request. The best you can do is use matchers to make your mocked server respond accordingly.
I would recommend you making some unit or integration tests with plain jUnit in order to test requests/responses in such cases. They should be quicker if you want to test that receipt requests are responding correctly. I see WireMock as an alternative to do acceptance test, to ensure that your interface with other REST services are not getting broken.
I've never used wiremock. But according to their online documentation you can write a mock that matches URL and Request body parameters. So you should be able to return different mocks depending on the parameters in either the URL itself or embedded in the request body.
Yes it is possible to create a stub with the request matching in wiremock.
Following attributes are supported by for Request matching request.
URL
HTTP Method
Query parameters
Headers
Basic authentication (a special case of header matching)
Cookies
Request body
Multipart/form-data
In your scenario if you want to apply matching on the values in the request body you can use the below approach for generating stub for it.
{
"request": {
...
"bodyPatterns" : [ {
"equalToJson" : "{ \"total_results\": 4 }"
} ]
...
},
...
}
Follow the link for more details: http://wiremock.org/docs/request-matching/

How do I unit test code which calls the Jersey Client API?

I wrote code which calls the Jersey client API which in turn calls a web service which is out of my control. I do not want my unit test to call the actual web service.
What is the best approach for writing a unit test for code which calls the Jersey client API? Should I use the Jersey server API to write a JAX-RS web service and then use the Jersey Test Framework for the unit test? Or should I mock out the Jersey web service calls? I have access to JMock. Or should I try another approach?
During my research, I found this discussion describing various options, but I did find a complete solution. Are there any code examples available showing a suggested JUnit approach? I could not find any in the Jersey documentation.
Here is the relevant source code:
public String getResult(URI uri) throws Exception {
// error handling code removed for clarity
ClientConfig clientConfig = new DefaultClientConfig();
Client client = Client.create(clientConfig);
WebResource service = client.resource(uri);
String result = service.accept(accept).get(String.class);
return result;
}
Here are examples of test code I would like to pass. I would like to test (1) passing in a valid URI and getting a valid string back and (2) passing in an invalid (for whatever reason -- unreachable or unauthorized) URI and getting an exception back.
#Test
public void testGetResult_ValidUri() throws Exception {
String xml = retriever.getResult(VALID_URI);
Assert.assertFalse(StringUtils.isBlank(xml));
}
#Test(expected = IllegalArgumentException.class)
public void testGetResult_InvalidUri() throws Exception {
retriever.getResult(INVALID_URI);
}
Everything above is the simple description of what my code does. In reality, there is a layer on top of that that accepts two URIs, first tries calling the first URI, and if that URI fails then it tries calling the second URI. I would like to have unit tests covering (1) the first URI succeeds, (2) the first URI fails and the second URI succeeds, and (3) both URIs fail. This code is sufficiently complex that I want to test these different scenarios using JUnit, but to do this I either need to run actual stand-in web services or mock out the Jersey client API calls.
Try to use Mockito or Easymock for mocking service calls. You need to mock only these methods which are actually used - no need to mock every method. You can creat mock object for WebResource class, then mock accept method call.
In #BeforeClass/#Before JUnit test method write something like (Mockito example)
WebResource res = mock(WebResource.class);
when(res.accept(something)).thenReturn(thatWhatYouWant);
Then in your tests you can use res object as if it was real object and call mock method on it. Instead of returning value you can also throw exceptions. Mockito is pretty cool.
Typically what you are really after is "does the way I use the Jersey Client DSL produce a request to the correct URL with the correct payload and URL parameters". Testing this with Mockito is really verbose and the setup code will usually end up looking something like this:
when(authentication.queryParam(eq("sa"), anyBoolean())).thenReturn(testAuthentication);
when(testAuthentication.resolveTemplate("channel", "smf")).thenReturn(testAuthentication);
when(testAuthentication.request(
MediaType.APPLICATION_JSON_TYPE)).thenReturn(mockRequestBuilder);
when(mockRequestBuilder.post(any(Entity.class))).thenReturn(mockResponse);
when(mockResponse.readEntity(ResponseWrapper.class)).thenReturn(successfulAuthResponse());
And this is basically just for a single REST request. It's overly verbose, and instead of testing the hoped outcome you are just replicating the steps you think are correct in using the Jersey Client DSL.
Instead of the above, I would aim for mocking a simple service. For this I've used WireMock which starts a Jetty server and where I can stub things like "expect a request to this URL, respond with this message and verify that the payload is this".
I know this is edging on an integration test and it is a bit slower than just using Mockito but I value testing the real outcome and I value the readability of the tests way more in this case.
Setup for a WireMock based Jersey Client test looks something like this:
#Test
public void exactUrlOnly() {
stubFor(get(urlEqualTo("/some/thing"))
.willReturn(aResponse()
.withHeader("Content-Type", "text/plain")
.withBody("Hello world!")));
assertThat(testClient.get("/some/thing").statusCode(), is(200));
assertThat(testClient.get("/some/thing/else").statusCode(), is(404));
}
Just implement a work-alike service and in your unit test setup start the service using HttpServerFactory.

Categories

Resources