I have an integration test for rest api microservers that stubs some of the external resources. Most of them work, but there is a particular one which becomes not available during the test.
Other tests stubbed the same way work
Given stubbing works when request is sent directly from the test or if called from postman while test is in Thread.sleep()
Stubbing does not work when the same request as used above is sent from one of the microservices called by the test or from postman if a microservice is paused (paused on a debug breakpoint). Other stubs work in these conditions.
#ClassRule
public static WireMockRule wireMockRule = new WireMockRule(
wireMockConfig()
.port(8080)
.usingFilesUnderDirectory("src/integration-test/resources"));
public static void stubExtService(WireMockRule wireMockRule) {
wireMockRule.stubFor(post(urlPathEqualTo("/my/url"))
.willReturn(aResponse().withHeader("Content-Type", "application/json")
.withStatus(200)
.withBodyFile("json/response.json")));
}
It sounds like the issue is that the test is finishing and WireMock shutting down before the async operation has completed. In this situation you can use Awaitility to wait (polling) for an expected request.
Here's an example in WireMock's tests:
https://github.com/tomakehurst/wiremock/blob/master/src/test/java/com/github/tomakehurst/wiremock/PostServeActionExtensionTest.java#L85
Although I have not located it in the code yet, my entry point service was responding and then processing the request asynchronously. Meanwhile, the test was receiving the response and shutting down along with WireMock, and microservices could not access the mocked resource any longer.
Related
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.
Abstract: how do devs Integration TEST timeouts for http requests?
Backstory: My team is having issues related to unusually long lasting HTTP web requests. We use the commons-httpclient version 3 by Apache. The code looks similar to this:
PostMethod post = new PostMethod(endpoint);
post.getParams().setSoTimeout(someInt);
httpClient.executeMethod(post);
The time to complete this request is usually acceptable (2 seconds or so), but occasionally, we will see 50-60 second requests despite having our SO timeout set to 4 seconds. This prompted me to do some research and found that most people are setting Connection Timeouts ANNNNND SO timeouts. It appears that SO timeouts should be set lower (as they simply time the distance between bytes in transit) and the the connection timeout is what we originally planned to use (i.e. initial delay between request and 1st byte returned).
Here is the code we scraped and plan on using:
httpClient.getHttpConnectionManager().getParams()
.setConnectionTimeout(someInt);
httpClient.getHttpConnectionManager().getParams()
.setSoTimeout(someInt);
The main pain here is that we are unable to integration test this change. More precisely, we are confused on how to integration test the delays coming from a socket connection to a foreign server. After digging through the commons-httpclient, I see protected and private classes that we will have to reproduce (because they are unextendable and unusable from outside the class), mock and string together the classes to ultimately get down to the socket class in java (which relies on a java native method -- which we would also need to reproduce and inject via mocks -- something I dont see frequently at that level).
The reason I am reaching out to Stack Overflow is to see how others are testing this/not testing this. I want to avoid testing this functionality in a performance environment at all costs.
Another thought of mine was to set up a mockserver to respond to the httpclient with a programmable delay time. I haven't seen an example of that yet.
First of all, there is no such thing as unit testing http requests - that would be integration testing.
Secondly, you can use a tool like JMeter to send http requests and test whether the response is being received in a certain amount of time as shown here in JMeter.
Taking the mock server route, I managed to set up a small web server with an API endpoint that I could test against. Here is the related code:
Lightweight server setup:
TJWSEmbeddedJaxrsServer server = new TJWSEmbeddedJaxrsServer();
server.setPort(SERVER_PORT);
server.getDeployment().getResources().add(new TestResource());
server.start();
API Endpoint:
/**
* In order to test the timeout, the resource will be injected into an embedded server.
* Each endpoint should have a unique use case.
*/
#Path("tests")
public class TestResource {
#POST
#Produces({MediaType.APPLICATION_XML})
#Path("socket-timeout")
public Response testSocketTimeout() throws InterruptedException {
Thread.sleep(SOCKET_TIMEOUT_SLEEP);
return Response.ok().build();
}
}
Within the api endpoint related class, I can control the sleep timeout which then triggers a socket timeout within the httpclient class. Its a bit hacky, but it works to test the functionality in the way I wanted to (simple, lightweight and effective).
I have a class and a method which looks like this
class A {
private RetryLogic logic;
private Service serviceClient;
public A(){
logic = new RetryLogic();
serviceClient = new Service();
}
public Response methodA() {
Request request = new Request();
serviceClient.addRetryLogic(logic);
Responce response = serviceClient.call(request);
return response;
}
}
The retry logic in this case will retry the service call if there is a failure like Service not available or any HTTP error.
But it won't retry if the service is getting called and throwing any modeled exceptions.
If I am writing a unit test for methodA is it appropriate (or should I be concerned) to test the retry logic by adding a test which would mock an HTTP exception and check if the retry works ?
The RetryLogic is basically a different package not owned by me.
Would you test the setConnectionTimeout of the Apache Commons HttpClient? or the setAutoCommit of your JDBC Client? I wouldn't.
If you trust that Service as you trust the rest of your dependencies, it makes no sense to test it. Just imagine that there are 1000 developers using Service, and all of them are testing the retry functionality... it's a bit of waste of time, isn't it?
I'm writing a REST service with Spring Web 4.0.5 and one of called methods is sending e-mail (with javax mail). Sending mail takes some time, but I would like to be able to send HTTP response (no matter what response, e.g. 200) BEFORE this method finishes - so before the mail is sent. Is it even possible? Preferably without multithreading?
#RestController
#RequestMapping(value = "/mails", produces = "application/json")
public class RestMailService{
#Autowired
MailService mailService;
#RequestMapping(value="/test", method = RequestMethod.GET)
public void sendMail(){
mailService.sendMail();
}
}
I believe all possible solutions include multithreading. The thread will be either directly started by you or hidden behind messaging or something similar.
if you were to go with multi-threading after all please use some Executor instead of below suggested new Thread(...).start()
I would also note that returning HTTP 200 before the operation finishes may somewhat confuse the user as the code suggests the operation was successful where in fact the operation maybe didn't even start yet.
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.