rest assured test failing intermittently due to data missing in the response - java

I have a rest assured test where I am converting the json into the java object and asserting on the java object.In the response object there is a particular value that I am asserting on in the test. When I run the service manually using POSTMAN I always see the parameter value in the response but when my automation tests execute the value is not always present in the response object.
I am suspecting it can be the issue from the service side not sending the consistent response but when hit manually the value is always present.
Test code:
#Test
public void validateResponse() {
RequestObject.name= "Hello";
RequestObject.age="20";
ResponseObject responseObject= given()
.contentType(TestData.CONTENT_TYPE_FOR_TEST)
.body(RequestObject)
.then()
.log()
.everything()
.when()
.post(uri)
.as(ResponseObject.class);
assertNotNull(responseObject.name);
assertNotNull(responseObject.year.age);
I think my test is simple not complicated but the assertion fails intermittently.
Any insight of how to debug more on this?

Your fields in RequestObject looks static and I think it's quite likely the JSON object mapper won't bind the result to static fields. Try make them non-static.

Related

rest-assured body(InputStream) does not work

I am using rest-assured 4.3.3 (the version is forced by the newest Spring Boot 2.5.0).
Rest-assured interprets the InputStream as Object and cannot handle it. When I press Ctrl+Q in IntelliJ IDEA (Javadoc) over .body(getInputStream()), it shows the signature RequestSpecification body(InputStream body) so the compiler should understand properly which of the the heavily overloaded .body() methods is supposed to be used.
However, when I replace getInputStream() with getFile(), it works. That's how I know that the XML in the resource file is correct.
The documentation says for both the methods body(File body) as well as body(InputStream body) exactly the same:
Specify file content that'll be sent with the request.
So my understanding is that these are just two alternative ways how to pass the body if I have it in a file.
My code:
class MyTest {
#Value("classpath:/valid-request.xml")
private Resource validRequest;
....
#Test
void myTest() {
given()
.header("Content-Type", "text/xml; charset=UTF-8")
.header("SOAPAction", "myService")
.body(validRequest.getInputStream()) // this does not work
// .body(validRequest.getFile()) // this works
.when()
.post("/myApi")
.then()
.log().ifValidationFails()
.statusCode(200)
.contentType("text/xml")
;
}
}
Error message:
java.io.BufferedInputStream#6ceb953
2021-06-11 17:35:47.083 ERROR [,628aa0b986fe0c98,628aa0b986fe0c98] 11428 --- [o-auto-1-exec-1] com.sun.xml.messaging.saaj.soap : SAAJ0511: Unable to create envelope from given source
I think that it is caused by a bug in rest-assured, but just for a check, maybe you might spot a flaw in my code better than I.
Anyway, I created an issue https://github.com/rest-assured/rest-assured/issues/1480.
The same error has been reported as "fixed" in the closed issue https://github.com/rest-assured/rest-assured/issues/1040.
Actually no, it's not a bug.
It says InputStream as a method parameter, because it expects that you will pass an object, which will be interpreted and serialized by InputStream.
The best way is to use POJO-classes for request body payloads, however in your case I'd suggest to go ahead and read that file as a String and pass as a param into body(), this should be working.

TestRestTemplate throws exception for 4xx status codes

I am writing component tests for a Spring-Boot application, to test my security configuration. I am therefore running tests that should test for both successful responses as well as "forbidden" status.
The problem I'm encountering is that because my REST call expects a complex JSON, for blocked calls the tests fail because TestRestTemplate is trying to deserialize a response body that is not there.
I am running a Spring-Boot application, and the tests class is annotated with:
#SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
I am trying to test a REST API that should return a list of users.
A simplified version of the call would be:
ResponseEntity<List<User>> responseEntity = testRestTemplate.exchange(URL, HttpMethod.GET, entity, new ParameterizedTypeReference<List<User>>() {});
where the TestRestTemplate is autowired by Spring, and the entity contains the authorization information.
For unauthorized request, I am getting an error like:
org.springframework.web.client.RestClientException: Error while extracting response for type [java.util.List<my.package.User>] and content type [application/json;charset=UTF-8]; nested exception is org.springframework.http.converter.HttpMessageNotReadableException: JSON parse error: Cannot deserialize instance of `java.util.ArrayList` out of START_OBJECT token; nested exception is com.fasterxml.jackson.databind.exc.MismatchedInputException: Cannot deserialize instance of `java.util.ArrayList` out of START_OBJECT token
at [Source: (PushbackInputStream); line: 1, column: 1]
If I change the response entity to receive String instead of List, I receive the response and can check the status and see that it is "forbidden"
ResponseEntity<String> responseEntity = testRestTemplate.exchange(URL, HttpMethod.GET, null, String.class);
I know I can work around this by:
Using String and deserializing with Gson, or
Using RestTemplate instead of TestRestTemplate and handling the HttpStatusCodeException, or
Overriding methods to not try to deserialize when status code is not 2xx
but since TestRestTemplate is supposed to be a fault-tolerant convenience subclass, I would have expected it to out-of-the-box not try to deserialize on error response.
Am I missing something here? Am I using it wrong?
Apologies for resurrecting this almost 2-year-old question, but I ran into a very similar problem while working with Spring TestRestTemplate and negative validation tests.
As Martin mentioned in his answer, TestRestTemplate does not include the ResponseErrorHandler that is normally associated with the proper RestTemplate. But the body of the response will still contain an error message instead of a list of User.
In my case, my web-app had #ControllerAdvice that wrapped all the common validation errors (MethodArgumentNotValidException, MethodArgumentTypeMismatchException, etc) and returned an instance of my own class ErrorMessageDto. The controller will marshal that to JSON instead of the expected response.
My component test initially tried to catch HttpStatusCodeException because that is thrown by the normal RestTemplate. In the test, the exception was not thrown (because of the lack of ResponseErrorHandler) and my restTemplate.postForObject(path, request, MyResponse.class) simply returned an empty version of MyResponse.
After reading Martin's description and following links, I changed it to
ResponseEntity<ErrorMessageDto> responseEntity = restTemplate.postForEntity(path, request, ErrorMessageDto.class);
// Do assertions on the response code and body (using assertj)
assertThat(responseEntity.getStatusCode()).isEqualTo(HttpStatus.UNPROCESSABLE_ENTITY);
assertThat(responseEntity.getBody().getErrors())
.extracting("path", "message")
.contains(tuple("firstName", "size must be between 0 and 255"))
In your case, I am sure the error message you are returning is an instance of an error message class. You probably realized this with your suggestion of returning a String and marshalling manually. If you know what class your error message is representing, you can simply replace that as the type in your ResponseEntity.
I expect that implementing a ResponseErrorHandler could help you work-around this.
But for RestTemplate it's the default behavior to throw errors on non-success results, are you sure you did not yet override it? Maybe you could use a dedicated RestTemplate for your test.
Source: https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/web/client/HttpClientErrorException.html
Exception thrown when an HTTP 4xx is received.
For implementing a ResponseErrorHandler, see https://www.baeldung.com/spring-rest-template-error-handling
EDIT: Indeed for TestRestTemplate this is not default behavior its meant for integration tests with the following benefits:
the template behaves in a test-friendly way by not throwing exceptions on server-side errors
...
Redirects are not followed (so you can assert the response location).
Cookies are ignored (so the template is stateless).
In your case you promise in your test code that a list of users is returned while this is not true, I would not expect the code to be resilient against that, I would even say that for that case a RestTemplate might make more sense.

Testing Rest Api methods

I'have to test the functions in rest api class that i created, I'm unable to get the functions of the created api class inside the test class, I haven't do the testing coding before. I need some guides to follow .
#POST
#Produces("text/plain")
#Path("/notifications/login/")
#HeaderParam("encoded")
Response login(#HeaderParam("encoded") String encoded, #QueryParam("tenantId") String tenantId) throws NotificationManagementException;
Its a function that i created, im not giving whole function body here, i need to know how to test this function. I'm giving a request call in javascript.
Unless there is some reason why you really don't want to, you could make the method public, and then you would be able to see it inside the test class.
i.e.
public Response login(...)
In the test you can then make a new instance of the class and call the method normally.
e.g.
#Test
public void shouldDoSomething(){
SomeClass someClass = new SomeClass();
someClass.login(...);
//some assertions or verifications
}
Two ways:
Use Postman to send post request.
Follow Spring-rest-client to create a rest client for test.
You can test with Postman a great chrome extension tool for REST based APIs. Run your server and hit the request from Postman. The image shows how to make a request.

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