Testing multiple controllers Spring 3.2

A strategy/framework for testing the controllers (the C in MVC) of a spring 3.2 restful webservices, using mocks and an auto bean decalarer to save time. A separate test contxt is loaded, and springs Mockmvc is used to perform comprehensive testing of URL’s and annotations.

A test will look something like this :

@WebAppConfiguration
public class MyCreateControllerTest extends BaseTestController {
  @Autowired
  MyService myService;
  @Test
  public void testCreate() throws Exception {
    MyDto dto = RandomDataFactory.getSingle(MyDto.class);
    when(myService.create((MyDto) any())).thenReturn(dto);
    String json = getAsJson(dto);
    MockHttpServletRequestBuilder mockHttpServletRequestBuilder =
        post("/MyApp/Create").contentType(MediaType.APPLICATION_JSON)
                             .content(json)
                             .accept(MediaType.APPLICATION_JSON);
    expectDto(mockHttpServletRequestBuilder,dto);
    verify(myService).create((MyDto) any()); //optional, the returned json is probably enough
  }
}

There are a number of things to notice, which will all be further explained.

The BaseTestController, the autowired service,the RandomDataFactory, the getAsJson() static method, and the call to expectDto().

  • The baseTestController  contains common config and the static method used by all tests classes; this is not particularly important as spring will cache a context if it used more than once –  I prefer to use an abstract base class for convenience.
  • The autowired service is noteworthy as a mock has been created automatically by an autobean decalarer itself defined as a bean in the testAppContext.xml.
  • A RandomDataFactory is simply used to populate beans, lists of beans and primitives with random data, code shown here.
  • GetasJson is a static method on base class that uses jackson to perform conversion of beans to json, so they can be used withinthe the mock requests.
  • ExpectDto is a convenience method that verifies the correct json has been returned, it is likely multiple tests/requests will return the same structures so pop it out to a separate method.

Starting at the beginging, the base test controller looks like this :

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = "classpath:controllerTestApplicationContext.xml")
public abstract class BaseTestController {

@Autowired
protected WebApplicationContext webApplicationContext;

protected MockMvc mockMvc;

@Before
public void initializeMockMvc() {
  mockMvc = webAppContextSetup(webApplicationContext).build();
}
protected static String getAsJson(Object object) throws IOException {
  ObjectWriter ow = new ObjectMapper().writer().withDefaultPrettyPrinter();
  return ow.writeValueAsString(object);
}

protected void expectException(MockHttpServletRequestBuilder mockHttpServletRequestBuilder) throws Exception {
  MvcResult mvcResult = this.mockMvc.perform(mockHttpServletRequestBuilder)
                                 // .andDo(print())
                                    .andExpect(status().isBadRequest())
                                    .andReturn();
  }
}

Everything should be relatively decipherable, as its standard spring stuff. The controllerTestApplicationContext.xml is stored within /src/test/resources – pastebinned because wordpress is lame.

So now there are only two items to further explain, the AutoBeanDeclarer and the MockPostProcessor, both pastebinned for brevity and better syntax highlighting.

If you notice in the test context definition, the only packages scanned are controller packages – this means that without the AutoBean decalrer you will get errors of no bean defined (when the controllers are scanned and find autowired service classes). However by coupling with the AutoBeanDeclarer we can automatically define dependices as mocks and the postprocessor simply stops mocks being further processed/scanned.

So before the tests begin we have all our controllers defined as they would be normally and all our service classes defined as mocks – automagically without having to define each bean.

Advertisements

Posted on August 10, 2013, in java, spring, unit testing. Bookmark the permalink. Leave a comment.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: