Using Ant Paths with the Grails Resources Plugin
December 17th, 2012
Using Ant Paths to enhance the Grails Resources plugin while organizing the code into modules with a common pattern.
Functionally testing a REST Client is simple with the new MockRestServiceServer if you are using Spring’s RestTemplate to power the client. This is a new feature in Spring 3.2.x but was available via the spring-test-mvc project starting with Spring 3.1.x (extra spring-test-mvc.jar required). The documentation is a little light in the spring reference manual so hopefully this example can help you piece it together.
Previously you might have had unit tests that mocked the RestTemplate but didn’t fully test the calls and error handling provided with the framework. Or you created an elaborate fake server environment just to spit back valid and invalid responses. MockRestServiceServer takes the approach of mocking the server and allowing you to specify expected behavior and responses in your junit test class. This allows you to fully test your handling of the RestTemplate client and server exception classes.
This example only shows how the mock server works. In a real environment you’d probably use RestTemplate with Jackson for object to json mapping and possibly Spring @Async for asynchronous calls.
SimpleRestService is a sample REST client that makes a call to a URL and handles successes and errors by returning them in the result string. We’ll use this as an example for our junit test cases:`
@Service
public class SimpleRestService {
@Autowired
private RestTemplate restTemplate;
public String getMessage() {
String result;
try {
String httpResult = restTemplate.getForObject("http://google.com",
String.class);
result = "Message SUCCESS result: " + httpResult;
} catch (HttpStatusCodeException e) {
result = "Get FAILED with HttpStatusCode: " + e.getStatusCode()
+ "|" + e.getStatusText();
} catch (RuntimeException e) {
result = "Get FAILEDn" + ExceptionUtils.getFullStackTrace(e);
}
return result;
}
}
``` `
The only real setup you need for testing is to configure your IDE to find the static imports. In Eclipse this is in Java>Editor>Content Assist>Favorites. Add these to go along with the hamcrest CoreMatchers and junit Assert that you probably already have. If using Spring 3.2.x: org.springframework.test.web.client.match.MockRestRequestMatchers org.springframework.test.web.client.response.MockRestResponseCreators If using Spring 3.1.x, the static import classes are named differently: org.springframework.test.web.client.match.RequestMatchers org.springframework.test.web.client.response.ResponseCreators
Each test will chain expect() and respond() methods. [MockRestRequestMatchers](http://static.springsource.org/spring/docs/3.2.x/javadoc-api/index.html?org/springframework/test/web/client/match/MockRestRequestMatchers.html) offers many hamcrest matchers to check your request URL, headers, HTTP method, and even json and xpath matchers to check body content. [MockRestResponseCreators](http://static.springsource.org/spring/docs/3.2.x/javadoc-api/index.html?org/springframework/test/web/client/response/MockRestResponseCreators.html) allows you to easily build both success and error responses.
Also, each test must call mockServer.verify() after the RestTemplate call is made to run the Mock Server assertions.
Setup the MockRestServiceServer in the setUp method: `<!-- TODO: Add language to code block -->
@Before
public void setUp() {
mockServer = MockRestServiceServer.createServer(restTemplate);
}
` `
testGetMessage() verifies our URL, GET HttpMethod, and returns a 200 Success with a text message of resultSuccess: `
@Test
public void testGetMessage() {
mockServer.expect(requestTo("http://google.com"))
.andExpect(method(HttpMethod.GET))
.andRespond(withSuccess("resultSuccess", MediaType.TEXT_PLAIN));
String result = simpleRestService.getMessage();
mockServer.verify();
assertThat(result, allOf(containsString("SUCCESS"),
containsString("resultSuccess")));
}
``` `
testGetMessage_404() shows a response with the specific 404 Not Found client http status code: `<!-- TODO: Add language to code block -->
@Test public void testGetMessage404() { mockServer.expect(requestTo(”http://google.com”)) .andExpect(method(HttpMethod.GET)) .andRespond(withStatus(HttpStatus.NOTFOUND));
String result = simpleRestService.getMessage();
mockServer.verify();
assertThat(result, allOf(containsString("FAILED"),
containsString("404")));
}
` `
testGetMessage_500() shows usage of the withServerError() convenience method: `
@Test
public void testGetMessage_500() {
mockServer.expect(requestTo("http://google.com"))
.andExpect(method(HttpMethod.GET))
.andRespond(withServerError());
String result = simpleRestService.getMessage();
mockServer.verify();
assertThat(result, allOf(containsString("FAILED"),
containsString("500")));
}
``` `
Additional matcher test examples can be found in the [spring-test-mvc](https://github.com/SpringSource/spring-framework/tree/master/spring-test-mvc/src/test/java/org/springframework/test/web/client/samples) section of the spring 3.2.x github repo.
Hopefully the new mock server in Spring helps you as much as it helped me, by cleaning up and reducing the amount of testing code required in both a reusable and standard fashion. The full java code from these examples are on [my github page](https://github.com/jeffsheets/MockRestServiceServerExample).
Jeff has developed Java, Groovy, Grails, and Javascript web apps for industries as varied as Defense, Energy, Weather, Insurance, and Telecom. He is a co-organizer of the Omaha Java Users Group. Jeff has worked on Grails projects since the Grails 1.3.x days, and has experience with production Groovy code as well as Spock tests and Gradle builds. His latest focus has been on AngularJS and Spring Boot applications using JHipster. Jeff also enjoys volunteering at local CoderDojo events to teach programming to our next generation.