How to handle real API URL via mock server? - java

I have a real API (https://profiles.production.service/api/person). And want to mock it using MockServer.
I'm using JUnit 5 in my integration test:
#Rule
val mockServer = MockServerContainer(DockerImageName.parse("jamesdbloom/mockserver:mockserver-5.11.2"))
mockServer.start()
....
MockServerClient("profiles.production.service", mockServer.serverPort)
.`when`(
request()
.withPath("/api/person")
.withQueryStringParameter("name", "peter")
)
.respond(
response()
.withBody("Peter the person!")
)
But actually got error:
org.mockserver.client.SocketConnectionException: Unable to resolve host profiles.production.service/<unresolved>:55070
How can I fix it?

This answer arrives too late for sure. But I am writing, just in case others come here and have a similar problem.
Looking at the documentation of the mockserver you can see an example that would make it work. Your code would need to change to:
MockServerClient(mockServer.getHost(), mockServer.getServerPort())
MockServerContainer is a docker image running on its own. So it will have a different URL than the server you need to mock.
If the problem you have is that you have hardcoded the server name on your class, then you would need to change that class. You will need to inject the server name. In your case
"https://%s:%d/api/person".format(mockServer.getHost(), mockServer.getServerPort())

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.

Micronaut: how to set an HttpClient URL after injection

I have the following method:
public HttpResponse<String> sendMessage(#NonNull String url, #NonNull String message) {
try (HttpClient client = HttpClient.create(new URL(url))) { ... }
}
Basically, what I want to achieve is to create the HttpClient with a URL that comes as a parameter to the method. It cannot be a property in a config file since it depends on some external conditions.
If I check the docs for the HttpClient.create() method it says that it should not be used within a Micronaut environment, and that the client should be injected instead. However, the problem is that if it's injected I cannot initialize it with my custom URL.
Another problem is that if I keep it with the HttpClient.create() method, if I want to unit test the class, I cannot mock the HttpClient. The best option would be to inject it via constructor to be able to create the tests.
What options do I have? I haven't been able to find this type of initialization. It looks like everyone uses a fix URL? 😅
Thanks!
I'll answer it myself. Apparently, you can specify in the request passed to the HttpClient methods (retrieve, exchange, etc.) both the relative and full URLs. So it doesn't matter what you put when you inject, instantiate the client.

Integration testing with spark server

I'm trying to IT my spark server. My intentions are to test all the controller functions.
I have thought about few options:
1. Set up a server that will start when running the tests, and terminate when the tests are over.
The problem with this solution is that I have to rewrite my whole server logic to the new server (we start server from scratch every time we set the server before the testing).
Initiate a controller from the test class (essential to initiate and not static call, in order to configure the right db to the controller) that will call the controller functions and check their answers.
This is my favorite one, but it means that I have to mock a spark request. I'm trying to build a spark request, and spark response objects, to send to my controller, and haven't found a single way to do that properly (and how to send parameters, set url routes etc..)
#Test
Public void testTry(){
String expectedName = "mark";
myController myCtl = new myController()
Request req = null;
Response res = null;
String childName = myCtl.getChildNameFromDB(req, res);
assertEquals(childName, expectedName);
}
The last one is to do the exact logic of the controller function in the test, and instead of getting the parameters from the request, ill initiate them myself.
For example, instead of:
String username = req.params(""usrName")
It will be:
Strimg username = "mark"
But that solution will demand copying a lot of code, and you might miss a little code line which might make the test succeed when in reality, the controller function fails (or doesn't deliver as wanted).
What do you think about Integratiom testing a spark driven server? I'm open minded to new solutions as well.
If you want to do integration testing, I would suggest to use your first approach, using a randomly chosen free TCP port and a HTTP client library (I often use the excellent HttpRequest library to that effect).
The main issue with this approach is that since Spark API is static, you won't be able to stop/start the server between test cases/suites.

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.

How do you unit test a servlet endpoint in apache camel?

I'm new to Camel and now have a simple route running in my Tomcat server. The route is built like this:
Processor generateWebResponse = new MySpecialProcessor();
from("servlet:///url?matchOnUriPrefix=true").process(generateWebResponse);
I tried a simple unit test like this:
Exchange lAuthRequest = createExchangeWithBody("[json body!]");
template.send("servlet:///url", lAuthRequest);
assertEquals("baseline body", lAuthRequest.getOut().getBody());
but get an exception indicating that I can't make a servlet endpoint. Here is the exception message:
org.apache.camel.FailedToCreateProducerException: Failed to create Producer for endpoint: Endpoint[servlet:///url]. Reason: java.lang.UnsupportedOperationException: You cannot create producer with servlet endpoint, please consider to use http or http4 endpoint.
This is new development so I don't have many constraints other than good design. I'm open to suggestions that require changes to the route. Also, if I'm doing something above that isn't idiomatic, I'm happy to revise the question with any suggested improvements.
You need to use a http client component to send a message to Tomcat, eg for example the camel--http component: http://camel.apache.org/http
You would then need to know the port number Tomcat runs the servlet at, eg
template.send("http://localhost:8080/myapp/myserver", lAuthRequest);
You would need to add camel-http to your classpath, eg if you use maven then add it as a dependency.
I solved my problem by breaking the route into two parts. Now the route declaration looks like this:
from("servlet:///auth?matchOnUriPrefix=true").inOut("direct:auth");
from("direct:auth").process(new AuthorizationProcessor());
And the test looks like this:
Exchange lAuthRequest = createExchangeWithBody("test body");
template.send("direct:auth", lAuthRequest);
assertEquals("processed body", lAuthRequest.getOut().getBody());
This isn't a complete test, but allows me to get coverage of all of the route excluding the incoming servlet part. I think it's sufficient for the time being.

Categories

Resources