testing REST interface with Spring 3.2 and a session scoped bean
There are some nice articles around the “spring 3.2 testing capabilities” like the spring documentation itself, this blog and this blog.
I wanted to not only test one request/response action against my REST interface. I wanted to simulate and test more of a conversation as it typical happens in the UI.
Following REST interface I wanted to create and test:
@RequestMapping("/customer")
public interface RESTCustomer {
@RequestMapping(
method = RequestMethod.POST)
@ResponseBody
Customer create(@RequestParam("firstname") final String firstname,
@RequestParam("lastname") final String lastname);
@RequestMapping(
method = RequestMethod.DELETE)
@ResponseStatus(HttpStatus.OK)
void delete(@RequestParam("id") final String... customerIds);
@RequestMapping(
produces = MediaType.APPLICATION_JSON_VALUE,
method = RequestMethod.GET)
@ResponseBody
Collection<Customer> getAll();
@RequestMapping(
value = "/update",
method = RequestMethod.POST)
@ResponseBody
Customer update(@RequestParam("id") final String id, @RequestParam("firstname") final String firstname);
}
Following test steps I had in mind, to test the create method:
- Get a list of all customers and remember the count
- Create a new customer
- Check, that the ID of the returning Customer was updated
- Get again a list of all customers
- Check the size of the customer list before and after creation … they should differ between one entry/li>
The new Spring Framework version 3.2 introduced some nice feature to do REST testing with minimal effort.
To test such conversion, you need beside the WebApplicationContext a MockHttpSession which has to be used between different mockMvc calls, on one test case.
The following base test structure is required:
@RunWith(SpringJUnit4ClassRunner.class)
@WebAppConfiguration
@ContextConfiguration(
classes = {
MyConfig.class,
})
public class RESTCustomerTest {
@Autowired
private WebApplicationContext wac;
@Autowired
MockHttpSession session;
MockMvc mockMvc;
ObjectMapper jsonObjectMapper;
@Before
public void setup() {
mockMvc = MockMvcBuilders.webAppContextSetup(wac).build();
jsonObjectMapper = new ObjectMapper();
}
@Test
public void testCreate() throws Exception {
....
}
}
Let assume, there is an implementation of the RESTCustomer service interface like this:
@Component
public class CustomerResource implements RESTCustomer {
private final PlatformService service;
@Autowired
public CustomerResource(final PlatformService service) {
this.service = service;
}
@Override
public Customer create(final String firstname, final String lastname) {
...
return service.createCustomer(firstname, lastname);
}
@Override
public Collection<Customer> getAll() {
...
return service.getAllCustomers();
}
}
Assume also, that the autowired PlatformService is a Session scoped bean (somewhere configured inside the spring configuration).
Now our testing method can be like this:
int countCustomers() throws Exception {
final MvcResult mvcResult = mockMvc.perform(get("/customer").session(session).accept(MediaType.APPLICATION_JSON))
.andReturn();
final Collection<Customer> customers = getRawObjects(mvcResult);
return customers.size();
}
Collection<Customer> getRawObjects(final MvcResult mvcResult) throws Exception {
return jsonObjectMapper.readValue(mvcResult.getResponse().getContentAsString(),
new TypeReference<Collection<Customer>() {
});
}
Customer getRawObject(final MvcResult mvcResult) throws Exception {
return jsonObjectMapper.readValue(mvcResult.getResponse().getContentAsString(),
new TypeReference<Customer>() {
});
}
@Test
public void testCreate() throws Exception {
// get default customer list and count
final int originalCustomerSize = countCustomers();
// create new customer
final MvcResult mvcResult = mockMvc
.perform(
post("/customer/?firstname={firstname}&lastname={lastname}","testFirstname", "testLastName").session(session).accept(
MediaType.APPLICATION_JSON)).andExpect(status().isOk()).andReturn();
final Customer customerObject = getRawObject(mvcResult);
assertNotNull("id of new customer should not empty", customerObject.get("id"));
assertEquals("newly firstname should match", "testFirstname", customerObject.get("firstname");
// again get list of all customers and check, if one more is available
assertEquals("after new customer was created, the size should be one more", originalCustomerSize + 1, countCustomers());
}
To get such conversation to work, you need to pass the session with .session(session)
between the mockMvc
calls. Else, every new mockMvc call creates a new session and your test fail.
REMEMBER: The trick is to pass the autowired MockHttpSession between the mock MVC requests.
Einsortiert unter:
java,
spring Tagged:
base test,
conversation,
language java,
mvc,
REST,
scope,
session,
spring,
spring framework,
test
Syndicated 2013-02-27 18:00:24 from waffel's Weblog