Unit testing 使用Spring MockMvc*类测试Spring MVC控制器方法
我正在尝试测试以下Spring mvc控制器方法:Unit testing 使用Spring MockMvc*类测试Spring MVC控制器方法,unit-testing,spring-mvc,mocking,Unit Testing,Spring Mvc,Mocking,我正在尝试测试以下Spring mvc控制器方法: @RequestMapping(value = "/preferences/email", method = RequestMethod.POST, produces = "text/html") public String modifyEmail(@ModelAttribute @Validated({ Validation.EmailModification.class }) EmailInfo emailInfo, BindingResu
@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";
}
以下是EmailInfo
bean:
@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;
}
以下是测试类:
@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);
}
}
}
奇怪的是,我得到了以下输出:
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 = []
上述输出的测试失败,我不确定原因。我希望通过测试,因为电子邮件地址是可用的
有人能帮忙吗
编辑1:
以下情况也不起作用:
@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);
}
编辑2:
我能够得到的是使用上面的编辑1以及下面的测试:
@Test
public void test() throws Exception {
mockMvc.perform(post("/preferences/email")//
.param("email", "available@example.com"))//
.andDo(print())//
.andExpect(model().attributeHasNoErrors("emailInfo"));
}
Updae回复评论 在您的控制器中尝试
String email=emailInfo.getEmail();
如果(!preferencesService.isEmailAvailable(email)){
而不是if(!preferencesService.isEmailAvailable(emailInfo.getEmail()){
不确定,只是一个可能的解决方案
或尝试
when(preferencesService.isEmailAvailable(eq("newEmail@example.com"))).thenReturn(Boolean.TRUE);
when(preferencesService.isEmailAvailable(eq("notAvailable@example.com"))).thenReturn(Boolean.FALSE);
你使用Mockito来实现mocking吗
我不是100%确定,但以下是我如何理解您的代码
when(preferencesService.isEmailAvailable("notAvailable@example.com")).thenReturn(Boolean.FALSE);
如果首选项service.isEmailAvailable
返回true,则在模拟练习中强制返回false
因此,在模拟练习中首选项service.isEmailAvailable
将始终返回false
现在在您的控制器中
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)));
}
}
如果首选项service.isEmailAvailable
为false
,则!
将其设置为true
,这样代码将始终进入If
块中,您将得到字段错误
,因此测试失败
:
.param("email", "newEmail@example.com"))//
您正在将请求参数设置为字符串值。但是,您尚未显示从字符串到EmailInfo的转换
在测试中,您正在检查名为email的emailInfo字段
我不知道这是干什么用的
when(preferencesService.isEmailAvailable("notAvailable@example.com")).thenReturn(Boolean.FALSE);
应该怎么做,您已经使用autowired注入了您的preferenceService。Hi!我想指定在调用isEmailAvailable时使用参数notAvailable@example.com,则应返回false。从字符串转换为EmailInfo是什么意思?@balteo您的控制器方法采用EmailInfo emai类型的参数lInfo,hwoever你的测试提交了一个名为email的字符串。但是我只能传入字符串,可以吗?有办法传入对象/bean吗?顺便问一下,我尝试了.param(“emailInfo.email”newEmail@example.com"))
没有用…@balteo是的,没错,那么你如何将Covenrt转换为emaiLInfo?你需要一个转换服务/反序列化器我现在不转换任何东西。你能建议如何转换吗?但它不应该放在里面,因为我实际上并没有用参数notAvailable@example.com...