title: Testing a Spring MVC controller method with Spring MockMvc* classes
body: <p>I am trying to test the following Spring mvc controller method:</p>
  
  <pre><code>@RequestMapping(value = "/preferences/email", method = RequestMethod.POST, produces = "text/html")
  public String modifyEmail(@ModelAttribute @Validated({ Validation.EmailModification.class }) EmailInfo emailInfo, BindingResult bindingResult, Model model, Locale locale) {
      Member member = memberService.retrieveCurrentMember();
      if (!preferencesService.isEmailAvailable(emailInfo.getEmail())) {
          if (member.getEmail().equals(emailInfo.getEmail())) {
              bindingResult.addError(new FieldError("emailInfo", "email", messageSource.getMessage("controller.preferences.same_email", null, locale)));
          } else {
              bindingResult.addError(new FieldError("emailInfo", "email", messageSource.getMessage("controller.preferences.email_already_used", null, locale)));
          }
      }
      if (bindingResult.hasErrors()) {
          model.addAttribute("emailInfo", emailInfo);
          return "preferences";
      }
      preferencesService.modifyEmail(member, emailInfo.getEmail());
      return "redirect:/preferences/email";
  }
  </code></pre>
  
  <p>Here is the <code>EmailInfo</code> bean:</p>
  
  <pre><code>@RooEquals
  @RooJavaBean
  public class EmailInfo {
  
      @NotNull(groups = { Validation.EmailModification.class })
      @Pattern(regexp = "^[_a-z0-9-]+(\\.[_a-z0-9-]+)*@[a-z0-9-]+(\\.[a-z0-9-]+)+$", groups = { Validation.EmailModification.class })
      private String email;
  
      private boolean activated;
  
      private String token;
  }
  </code></pre>
  
  <p>Here is the test class:</p>
  
  <pre><code>@ContextConfiguration
  @WebAppConfiguration
  @RunWith(SpringJUnit4ClassRunner.class)
  public class PreferenceControllerTest {
  
      @Autowired
      private WebApplicationContext ctx;
  
      private MockMvc mockMvc;
  
      @Autowired
      private MemberService memberService;
  
      @Autowired
      private PreferencesService preferencesService;
  
      @Autowired
      private MemberRepository memberRepository;
  
      @Autowired
      private SigninService signinService;
  
      @Autowired
      private MessageSource messageSource;
  
      @Before
      public void setup() {
          mockMvc = webAppContextSetup(ctx).build();
          Member currentMember = new Member();
          currentMember.setEmail("currentMember@example.com");
          when(memberService.retrieveCurrentMember()).thenReturn(currentMember);
          when(preferencesService.isEmailAvailable("notAvailable@example.com")).thenReturn(Boolean.FALSE);
      }
  
      @Test
      public void test() throws Exception {
          mockMvc.perform(post("/preferences/email")//
                  .param("email", "newEmail@example.com"))//
                  .andDo(print()).andExpect(model().attributeHasNoErrors("emailInfo", "email"));
      }
  
      @Configuration
      public static class testConfiguration {
          @Bean
          public PreferenceController preferenceController() {
              return new PreferenceController();
          }
  
          @Bean
          public PreferencesService preferenceService() {
              return mock(PreferencesService.class);
          }
  
          @Bean
          public MemberService memberService() {
              return mock(MemberService.class);
          }
  
          @Bean
          public MemberRepository memberRepository() {
              return mock(MemberRepository.class);
          }
  
          @Bean
          public SigninService signinService() {
              return mock(SigninService.class);
          }
  
          @Bean
          public MessageSource messageSource() {
              return mock(MessageSource.class);
          }
  
      }
  }
  </code></pre>
  
  <p>Curiously I get the following output:</p>
  
  <pre><code>MockHttpServletRequest:
           HTTP Method = POST
           Request URI = /preferences/email
            Parameters = {email=[newEmail@example.com]}
               Headers = {}
  
               Handler:
                  Type = com.bignibou.controller.PreferenceController
  
                 Async:
     Was async started = false
          Async result = null
  
    Resolved Exception:
                  Type = null
  
          ModelAndView:
             View name = preferences
                  View = null
             Attribute = emailInfo
                 value = com.bignibou.controller.helpers.EmailInfo@9a56c123
                errors = [Field error in object 'emailInfo' on field 'email': rejected value [null]; codes []; arguments []; default message [null]]
  
              FlashMap:
  
  MockHttpServletResponse:
                Status = 200
         Error message = null
               Headers = {}
          Content type = null
                  Body = 
         Forwarded URL = preferences
        Redirected URL = null
               Cookies = []
  </code></pre>
  
  <p>The test fails with the above output and I am not sure why. I expected the test to pass as the email address is available.</p>
  
  <p>Can anyone please help?</p>
  
  <p><strong>edit 1</strong>:</p>
  
  <p>The following is not working either:</p>
  
  <pre><code>@Before
      public void setup() {
          mockMvc = webAppContextSetup(ctx).build();
          Member currentMember = new Member();
          currentMember.setEmail("currentMember@example.com");
          when(memberService.retrieveCurrentMember()).thenReturn(currentMember);
          when(preferencesService.isEmailAvailable(eq("notAvailable@example.com"))).thenReturn(Boolean.FALSE);
          when(preferencesService.isEmailAvailable(eq("newEmail@example.com"))).thenReturn(Boolean.TRUE);
      }
  </code></pre>
  
  <p><strong>edit 2</strong>:</p>
  
  <p>I was able to get is to work with the above <strong>edit 1</strong> plus the test below:</p>
  
  <pre><code>@Test
      public void test() throws Exception {
          mockMvc.perform(post("/preferences/email")//
                  .param("email", "available@example.com"))//
                  .andDo(print())//
                  .andExpect(model().attributeHasNoErrors("emailInfo"));
      }
  </code></pre>