I'm trying to run some integration tests on my code and I use a MockRestServiceServer from spring-boot-test in order to set up the expected requests.
I have one call that is called many times while running my test, but it seems not to persist during the test. My test looks like this:
#Test
void getHealthStatus() {
try {
RequestBuilder request = get("/actuator/hc").contentType("application/json");
MockServerBinder.bindPersistentThingworxPropertiesCall(
mockServer,
requestTo(new URI(String.format("%sProperties/TestProp", thingworxUrl))),
objectMapper.writeValueAsString(new PingResponse(DashboardIndicator.HEALTHY, 200))
);
DashboardStatusModel expectedResult = new DashboardStatusModel();
expectedResult.addResult("spring",service.getAppHealth());
expectedResult.addResult("thingworx", service.getThingworxAvailability());
assertOpenUrl(request);
MvcResult result = mockMvc.perform(get("/actuator/hc").contentType("application/json"))
.andExpect(status().isOk())
.andReturn();
DashboardStatusModel actualResult = objectMapper.readValue(result.getResponse().getContentAsString(), DashboardStatusModel.class);
assertEquals(expectedResult.getResults().get("spring"), actualResult.getResults().get("spring"));
assertEquals(expectedResult.getResults().get("thingworx").getStatus(),actualResult.getResults().get("thingworx").getStatus());
assertEquals(expectedResult.getResults().get("thingworx").getData().get("url"), actualResult.getResults().get("thingworx").getData().get("url"));
} catch (Exception e) {
fail("Unable to perform REST call on GDP-API", e);
}
}
As additional information:
mockServer is created in a superclass like this:
protected static MockRestServiceServer mockServer;
#BeforeEach
public void configureMockServer() {
mockServer = MockRestServiceServer.bindTo(restTemplate).ignoreExpectOrder(true).build();
}
MockServerBinder.bindPersistentThingworxPropertiesCall() is a helper class that looks like this:
public static void bindPersistentThingworxPropertiesCall(MockRestServiceServer mockServer, RequestMatcher request, String responseJSONasString){
mockServer.expect(ExpectedCount.once(), request)
.andExpect(method(HttpMethod.GET))
.andRespond(withStatus(HttpStatus.OK)
.contentType(MediaType.APPLICATION_JSON)
.body(responseJSONasString));
}
assertOpenUrl(request); is a function that checks if a URL doesn't have any authentication by using a MockMVC:
public void assertOpenUrl(RequestBuilder request){
try{
mockMvc.perform(request).andExpect(status().isOk());
} catch (Exception e) {
fail("Unable to perform REST call on GDP-API", e);
}
}
When I run this test, the expectedResult.addResult("thingworx", service.getThingworxAvailability()); will be able to use the MockRestServiceServer, but the assertOpenUrl(request); line will fail, because MockRestServiceServer doesn't expect anymore calls to the endpoint binded in MockServerBinder.bindPersistantThingworxPropertyCall(). This does not happen if I Copy & Paste MockServerBinder.bindPersistantThingworxPropertyCall() under the existing one, so I think it's a problem with how I binded the request in the first place.
From what I understand ExpectedCount.manyTimes() should keep this request during the test.
Is this not true or is there another way I should bind my request so that it stays available during the entire test?
PEBCAK issue.
As you can see in the bindPersistentThingworxPropertiesCall(), I actually didn't use ExpectedCount.manyTimes(). I didn't catch that. Changed it and now it works.
Related
I have created a custom extension (Connector), which sends an HttpRequest (using org.mule.runtime.http.api.client.HttpClient and the related classes).
The extension's unit tests file contains the following test, to which I've added a simple Mockito mock to throw a TimeoutException when the HTTP request is being sent:
public class DemoOperationsTestCase extends MuleArtifactFunctionalTestCase {
/**
* Specifies the mule config xml with the flows that are going to be executed in the tests, this file lives in the test resources.
*/
#Override
protected String getConfigFile() {
return "test-mule-config.xml";
}
#Test
public void executeSayHiOperation() throws Exception {
HttpClient httpClient = mock(HttpClient.class);
HttpRequest httpRequest = mock(HttpRequest.class);
when(httpClient.send(any(HttpRequest.class), anyInt(), anyBoolean(), any(HttpAuthentication.class))).thenThrow(new TimeoutException());
String payloadValue = ((String) flowRunner("sayHiFlow").run()
.getMessage()
.getPayload()
.getValue());
assertThat(payloadValue, is("Hello Mariano Gonzalez!!!"));
}
}
The test should fail because the function should throw a TimeoutException, it is what I want for now.
The code that is being tested is as follows (redacted for convenience):
HttpClient client = connection.getHttpClient();
HttpResponse httpResponse = null;
String response = "N/A";
HttpRequestBuilder builder = HttpRequest.builder();
try {
httpResponse = client
.send(builder
.addHeader("Authorization", authorization)
.method("POST")
.entity(new ByteArrayHttpEntity("Hello from Mule Connector!".getBytes()))
.uri(destinationUrl)
.build(),
0, false, null);
response = IOUtils.toString(httpResponse.getEntity().getContent());
} catch (IOException e) {
e.printStackTrace();
throw new ModuleException(DemoError.NO_RESPONSE, new Exception("Failed to get response"));
} catch (TimeoutException e) {
e.printStackTrace();
throw new ModuleException(DemoError.NO_RESPONSE, new Exception("Connection timed out"));
}
But I always get the "Failed to get response" error message, which is what I get when I run the Connector with a nonexistent server, therefore the mock isn't working (it actually tries to send an HTTP request).
I am new to Java unit testing, so it might be a general mocking issue and not specific to MuleSoft - though I came across other questions (such as this one and this one), I tried the suggestions in the answers and the comments, but I get the same error. I even tried to use thenReturn instead of thenThrow, and I get the same error - so the mock isn't working.
Any idea why this is happening?
I am trying to use JUnit4 test a utility method that takes a javax.ws.rs.core.Response as an input parameter. The method looks at the Response attributes and takes some action based on the response code. When I just create a response in my test method and submit it using:
Response resp = Response.status(Status.INTERNAL_SERVER_ERROR).entity(respMessage).build();
ResponseParser.parseResponse(resp);
My utility method throws:
java.lang.IllegalStateException: RESTEASY003290: Entity is not backed by an input stream
at org.jboss.resteasy.specimpl.BuiltResponse.readEntity(BuiltResponse.java:231)
at org.jboss.resteasy.specimpl.BuiltResponse.readEntity(BuiltResponse.java:218)
My util class is basically:
import javax.ws.rs.core.Response;
import javax.ws.rs.core.Response.Status.Family;
public class ResponseParser {
public static void parseResponse(Response response) {
String errorResp = "";
if (!response.getStatusInfo().getFamily().equals(Family.SUCCESSFUL)) {
int errorCode = response.getStatus();
errorResp = response.readEntity(String.class);
}
}
}
How can I create a response that will be properly backed by a stream as expected by resteasy? I looked at quite a few similar questions but they mostly seemed to be centered around testing or mocking an endpoint call. I just want to test my parsing method.
I did end up doing what #albert_nil suggested. Here is the relevant code from my test class. MessageParseUtil.parseReportResponse(mockResponse); is the utility method that is being tested.
#Test
public void parse_Report_Response_400_Test() {
String respMessage = "400 : Validation error occurred. Invalid Parm: employeeID";
Response mockResponse = buildMockResponse(Status.INTERNAL_SERVER_ERROR, respMessage);
try {
MessageParseUtil.parseReportResponse(mockResponse);
fail("Expected parseReportResponse() to throw error but none thrown.");
} catch (RestClientException e) {
Assert.assertEquals("Expected to status code to be 400 but was " + e.getStatusCode() + " instead.", 400, e.getStatusCode());
Assert.assertEquals("The error message was missing or not correct.", respMessage, e.getErrorMessage().getErrorMessageList().get(0));
}
}
private Response buildMockResponse(Status status, String msgEntity) {
Response mockResponse = mock(Response.class);
Mockito.when(mockResponse.readEntity(String.class)).thenReturn(msgEntity);
Mockito.when(mockResponse.getStatus()).thenReturn(status.getStatusCode());
Mockito.when(mockResponse.getStatusInfo()).thenReturn(status);
return mockResponse;
}
Mock the Response with some unit testing framework, like Mockito. Then you will be able to declare what to return on each response method call, or even check if a method has been called.
I am working in AWS(Amazon web service) , mockito and java junit4 environment. In my class I am using one method which takes Request object as a parameter and depending on that object I am getting response. Following is my code,
private Response<String> getStringResponse(Request<?> request) {
try {
AmazonHttpClient client = new AmazonHttpClient(new ClientConfiguration());
ExecutionContext executionContext = new ExecutionContext(true);
HttpResponseHandler<AmazonClientException> handler = getErrorResponseHandler();
HttpResponseHandler<String> responseHandler = getHttpResponseHandler();
RequestExecutionBuilder requestExecutionBuilder = client.requestExecutionBuilder();
requestExecutionBuilder = requestExecutionBuilder.executionContext(executionContext);
requestExecutionBuilder = requestExecutionBuilder.request(request);
requestExecutionBuilder = requestExecutionBuilder.errorResponseHandler(handler);
Response<String> response = requestExecutionBuilder.execute(responseHandler);
return response;
} catch (Exception e) {
AppLogger.getLogger().error("Exception in :: classname :: getStringResponse() ::");
throw e;
}
}
What I want to do is, I want to mock this whole scenario means on whatever request, my method should give me the custom response object which I want, irrespective of what Request is coming. I am calling this method from my junit test. So is there anyway to do this?
Before you can test this method with JUnit and Mockito,
you should write a clean and testable codes.
Importantly, you have to remove all dependencies inside method and initialize them from outside. For example,
private Response<String> getStringResponse(Request<?> request,
AmazonHttpClient client,
ExecutionContext executionContext,
HttpResponseHandler<AmazonClientException> handler,
HttpResponseHandler<String> responseHandler) {
try {
RequestExecutionBuilder requestExecutionBuilder = client.requestExecutionBuilder()
.executionContext(executionContext)
.request(request)
.errorResponseHandler(handler);
Response<String> response = requestExecutionBuilder.execute(responseHandler);
return response;
} catch (Exception e) {
AppLogger.getLogger().error("Exception in :: classname :: getStringResponse() ::");
throw e;
}
}
Now you can test it by mocking these above dependencies.
#Mock
AmazonHttpClient client;
#Mock
ExecutionContext executionContext;
#Mock
HttpResponseHandler<AmazonClientException> handler;
#Mock
HttpResponseHandler<String> responseHandler;
// For request, you can create a custom one or use mock data
Request<?> request;
#Before
public void setUp() {
MockitoAnnotations.initMocks(this);
// other setups
}
#Test
public void getStringResponseTest() {
// you can test now
yourCall.getStringResponse(request, client, executionContext, handler, responseHandler);
// verify whatever you want....
}
I have a function in controller class that calls a Rest Easy web service which returns a response. I need to unit test that particular function.
public void createOrderRequest(OrderModel orderModel, ResourceBundle resourceBundle, AspectModel aspectModel) {
try {
LOG.debug("Creating order request");
OrderReq orderRequest = new OrderReq();
orderRequest.getHeader().setDestination("http://localhost:8080/middleware/ws/services/txn/getReport");
orderRequest.setUserId("abc");
OrderResp response = (OrderResp) OrderService.getInstance().getOrderService().sendRequest(orderRequest);
if (response.getHeader().getErrorCode() == ErrorCode.SUCCESS.getErrorCode()) {
LOG.debug("Successfully send order request");
orderModel.setErrorDescription("Order successfully sent");
aspectModel.set(orderModel);
}
} catch (Exception ex) {
LOG.error("Error while sending order request: " + ex.getMessage());
}
}
I want to mock the order request object OrderReq and response object OrderResp. My intention is to create mock response for the rest easy web service request. How can I achieve it ?
The most simple way is to move the object creation into a help method which you can override in a test:
public void createOrderRequest(OrderModel orderModel, ResourceBundle resourceBundle, AspectModel aspectModel) {
try {
LOG.debug("Creating order request");
OrderReq orderRequest = createOrderReq();
....
}
}
/*test*/ OrderReq createOrderReq() { return new OrderReq(); }
Using package private (default) visibility, a test can override the method (since they are in the same package).
Alternatively, you can create a factory and inject that.
I am writing a Java class that uses Jersey under the hood to send an HTTP request to a RESTful API (3rd party).
I would also like to write a JUnit test that mocks the API sending back HTTP 500 responses. Being new to Jersey, it is tough for me to see what I have to do to mock these HTTP 500 responses.
So far here is my best attempt:
// The main class-under-test
public class MyJerseyAdaptor {
public void send() {
ClientConfig config = new DefaultClientConfig();
Client client = Client.create(config);
String uri = UriBuilder.fromUri("http://example.com/whatever").build();
WebResource service = client.resource(uri);
// I *believe* this is where Jersey actually makes the API call...
service.path("rest").path("somePath")
.accept(MediaType.TEXT_HTML).get(String.class);
}
}
#Test
public void sendThrowsOnHttp500() {
// GIVEN
MyJerseyAdaptor adaptor = new MyJerseyAdaptor();
// WHEN
try {
adaptor.send();
// THEN - we should never get here since we have mocked the server to
// return an HTTP 500
org.junit.Assert.fail();
}
catch(RuntimeException rte) {
;
}
}
I am familiar with Mockito but have no preference in mocking library. Basically if someone could just tell me which classes/methods need to be mocked to throw a HTTP 500 response I can figure out how to actually implement the mocks.
Try this:
WebResource service = client.resource(uri);
WebResource serviceSpy = Mockito.spy(service);
Mockito.doThrow(new RuntimeException("500!")).when(serviceSpy).get(Mockito.any(String.class));
serviceSpy.path("rest").path("somePath")
.accept(MediaType.TEXT_HTML).get(String.class);
I don't know jersey, but from my understanding, I think the actual call is done when get() method is invoked.
So you can just use a real WebResource object and replace the behavior of the get(String) method to throw the exception instead of actually execute the http call.
I'm writing a Jersey web application... and we throw WebApplicationException for HTTP error responses. You can simply pass the response code as the constructor-parameter. For example,
throw new WebApplicationException(500);
When this exception is thrown server-side, it shows up in my browser as a 500 HTTP response.
Not sure if this is what you want... but I thought the input might help! Best of luck.
I was able to simulate a 500 response with the following code:
#RunWith(MockitoJUnitRunner.class)
public class JerseyTest {
#Mock
private Client client;
#Mock
private WebResource resource;
#Mock
private WebResource.Builder resourceBuilder;
#InjectMocks
private Service service;
#Before
public void setUp() {
MockitoAnnotations.initMocks(this);
}
#Test
public void jerseyWith500() throws Exception {
// Mock the client to return expected resource
when(client.resource(anyString())).thenReturn(resource);
// Mock the builder
when(resource.accept(MediaType.APPLICATION_JSON)).thenReturn(resourceBuilder);
// Mock the response object to throw an error that simulates a 500 response
ClientResponse c = new ClientResponse(500, null, null, null);
// The buffered response needs to be false or else we get an NPE
// when it tries to read the null entity above.
UniformInterfaceException uie = new UniformInterfaceException(c, false);
when(resourceBuilder.get(String.class)).thenThrow(uie);
try {
service.get("/my/test/path");
} catch (Exception e) {
// Your assert logic for what should happen here.
}
}
}