Tag: mocking

Mock Testing Spring MVC Controller

I’m in the midst of implementing a Spring MVC based web application. We have hudson for continuous integration builds that run all of our unit tests, but testing spring MVC controllers still just isn’t quite as easy as I would hope. There is some information on testing the controllers in the official spring documentation, but for someone like me that’s not a spring guru, or just starting out, it wasn’t enough to get me going. I recently was introduced to Mockito, so I spent a bit of time today trying to get a test for our controller using Mockito. It was simple and took no time at all.

I have yet to try it in a more complex controller method, but I think it’ll work just fine , especially when I get some utilities in place to initialize the mock objects that are commonly used by the controller. As it stands, here’s what I did to get it going. This tests the controller as a POJO, without using any spring configuration or capabilities.

Here is the controller I wish to test. Obviously I stripped out a bunch of code not needed for this demonstration.

@Controller
@RequestMapping( "/admin/survey" )
public class SurveyAdminController
{
    
    @Resource
    private SurveyService surveyService;
    
    @Resource
    private UnitService unitService;
    
    @Resource
    private OrganizationService orgService;
    
    /**
     * Show the table of existing questions to the user
     * @param model
     * @return
     */
    @RequestMapping( "questions" )
    public ModelAndView listQuestions()
    {
        ModelAndView mav = new ModelAndView( "/admin/questionList");
        List<SurveyQuestion> questions = surveyService.findAllQuestions();
        mav.addObject( "questions", questions );
        List<UnitFeature> features = unitService.getAllFeatures();
        mav.addObject( "features", features );
        List<Organization> organizations = orgService.getAll();
        mav.addObject( "organizations", organizations );
        return mav;
    }
}

For this simple test, it’s just going to validate that the view name is correct, and that the model that’s returned contains the correct information.


package com.bi.controller;

import static org.junit.Assert.assertEquals;
import static org.mockito.Mockito.when;

import java.util.ArrayList;
import java.util.List;

import org.junit.Before;
import org.junit.Test;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import org.springframework.test.util.ReflectionTestUtils;
import org.springframework.web.servlet.ModelAndView;

import com.bi.data.OrganizationService;
import com.bi.data.SurveyService;
import com.bi.data.UnitService;
import com.bi.data.corp.Organization;
import com.bi.data.survey.SurveyQuestion;
import com.bi.data.unit.UnitFeature;
import com.bi.web.util.MessageUtil;

public class SurveyAdminControllerTest
{
    @Mock SurveyService surveyService;
    @Mock UnitService unitService;
    @Mock OrganizationService orgService;
    @Mock MessageUtil messageUtil;

    @Before
    public void setup()
    {
        // this must be called for the @Mock annotations above to be processed.
        MockitoAnnotations.initMocks( this );
    }
    
    @Test
    public void testListQuestions()
    {
        // setup our mock question list
        List<SurveyQuestion> questions = new ArrayList<SurveyQuestion>();
        questions.add( new SurveyQuestion( "asdf", null ));
        when( surveyService.findAllQuestions()).thenReturn( questions );

        // setup our mock feature list
        List<UnitFeature> features = new ArrayList<UnitFeature>();
        features.add( new UnitFeature( "TEST FEATURE" ));
        when( unitService.getAllFeatures()).thenReturn( features );

        // setup our mock organization list
        List<Organization> orgs = new ArrayList<Organization>();
        orgs.add( new Organization( "TEST ORGANIZATION" ));
        when( orgService.getAll()).thenReturn( orgs );

        // create an instance of the controller we want to test
        SurveyAdminController controller = new SurveyAdminController();

        // since we aren't using spring, these values won't be injected, so set them manually
        ReflectionTestUtils.setField( controller, "surveyService", surveyService );
        ReflectionTestUtils.setField( controller, "unitService", unitService );
        ReflectionTestUtils.setField( controller, "orgService", orgService );

        // call the method under test
        ModelAndView mav = controller.listQuestions();

        // review the results.
        assertEquals( questions, mav.getModel().get( "questions" ));
        assertEquals( features, mav.getModel().get( "features" ));
        assertEquals( orgs, mav.getModel().get( "organizations" ));
        assertEquals( "/admin/questionList", mav.getViewName());
    }
}

The comments should be pretty self explanatory in the test class. The awesomeness of Mockito is how you setup the mocks. A line like this:

        when( unitService.getAllFeatures()).thenReturn( features );

reads very nicely and sets up the return value for my service object, which keeps me from needing a database or anything setup in order to test my controller method. Mockito ftw.

Advertisements