Translations of this page:

Testing Spring Controllers with EasyMock

It took me a few minutes to grasp the utility of the EasyMock package. The package:

org.springframework.mock.web*

provides Mock versions of ServletRequest and ServletResponse so that Spring Controllers can be called and unit tested outside the scope of a servlet engine.

EasyMock on the other hand lets you replace all the code behind the controller, the Model, so you can test the controller’s business logic in isolation. This isn’t particularly useful if your controller is just a thin wrapper for some other process but often there is substantial processing of data in command objects before a layer, such as a database access, is called.

I wanted to test a Spring Controller that is responsible for creating and storing pages in my CMS. The first thing to do is extend the junit TestCase class. This provides the basic unit testing framework.

public class PageControllerTest extends TestCase {

I then declared two mock objects. These are the interfaces that the Controller under test calls to carry out its work. WebPageDAO is responsible for accessing the backing store and Templates manages the templates that provide the look and feel of the returned page.

WebPageDAO webPageDAOMock;
Templates templatesMock;

I did some configuration in the setup method. After declaring the Spring controller I get EasyMock to create mock versions of my two objects. I then train my templates mock object, this takes no parameters but returns a list of templates. I do this once here because it is common to all method calls.

protected void setUp() throws Exception {
	pageController = new PageController();
 
	webPageDAOMock = createMock(WebPageDAO.class);
	templatesMock = createMock(Templates.class);
 
	Template template = new Template();
	template.setName("simple");
	template.setFormat("<contents>mycontents</contents>");
	template.setDescription("Simple Template");
	HashMap<String, Template> templateList = new HashMap<String, Template>();
	templateList.put("simple", template);

The expect method tells EasyMock what data a call to the templates’ getTemplates() method should expect during the test and what to return, in this case a HashMap of template objects.

expect(templatesMock.getTemplates()).andReturn(templateList);

We then inject the two objects into the controller just as Spring would do.

pageController.setWebPageDAO(webPageDAOMock);
pageController.setTemplates(templatesMock);

The Page command object changes with each unit test. So we train it in each test. This is the code to test the saving of pages. Here we see the mock servlet request and response objects in action. The data is posted to the controller and consists of a page command object plus the actual page contents which is access by the controller by a call to

request.getInputStream()

The save page controller strips off the surrounding <contents> elements before saving this data. In the unit test we set up the page contents and pass it to the request object.

public void testSavePage() throws Exception {
	MockHttpServletRequest request = new MockHttpServletRequest();
	request.setMethod("POST");
	byte content[] = "<contents>this is some contents</contents>".getBytes();
	request.setContent(content);

We then create the Page controller and set up its data.

Page page = new Page();
 
page.setTemplate("simple");
page.setKeywords("kw1, kw2");
page.setTitle("my title");
page.setPath("/index.htm");
page.setUuid("1234:5678");

And finally we tell the WebPageDAO mock object that it will receive the contents we set up above as a parameter along with the page UUID and that it will return a path string to the create page. If the actual date passed by the savePage() method differs the unit test will fail.

expect(webPageDAOMock.updatePageContent("this is some contents", page.getUuid())).andReturn(page.getPath());

We then set both objects into test mode with the replay method. This resets method call counters etc for a new test.

replay(webPageDAOMock);
replay(templatesMock);
 
request.setRequestURI("http://localhost:8080/magneato/abc/index.htm");
HttpServletResponse response = new MockHttpServletResponse();

After calling our method we should get a ModelAndView object. This should not be null and should contain a redirect directive, as we test below.

ModelAndView modelAndView = pageController.savePage(request, response, page);
assertNotNull("ModelAndView should not be null", modelAndView);
System.out.println(modelAndView.getViewName());
assertEquals(modelAndView.getViewName(), "redirect:" + page.getPath());

What we have done is test just the code in the savePage method in isolation from Spring and the Servlet container. We make sure that the data passed to the Model is correct and test the data returned to the View.

One thing to remember is the classes you pass to EasyMock to set up your mock objects should be interfaces rather than implementations. This encourages the practice of programming to interfaces but may need some refactoring. In addition if your controller requires any support from the Servlet or Spring container that cannot be set up with the mock servlet request and response objects it may also require code changes.

tech/java/testing-spring-controllers-with-easymock.txt · Last modified: 2009/09/23 16:14 by davidof
Recent changes RSS feed