问题
I want to test a controller which is using @ModelAttribute
for one of its method arguments.
public String processSaveAction(@ModelAttribute("exampleEntity") ExampleEntity exampleEntity)
@ModelAttribute
method getExampleEntity
is using @RequestParam
:
@ModelAttribute("exampleEntity")
public ExampleEntity getExampleEntity(@RequestParam(value = "id", required = true) ExampleEntity exampleEntity) {
My controller is using WebDataBinder
to call a factory, which returns an object based on param "id".
@Controller
public class ExampleController(){
@Autowired private IdEditorFactory idEditorFactory;
@InitBinder
public void initBinder(WebDataBinder binder) {
binder.registerCustomEditor(ExampleEntity.class, idEditorFactory.createEditor(ExampleEntity.class));
}
@ModelAttribute("exampleEntity")
public ExampleEntity getExampleEntity(@RequestParam(value = "id", required = true) ExampleEntity exampleEntity) {
//Irrelevant operations
return exampleEntity;
}
@RequestMapping(method = RequestMethod.POST, params = "action=save")
public String processSaveAction(
@RequestParam(value = "confirmed") String exampleString,
@ModelAttribute("exampleEntity") ExampleEntity exampleEntity,
BindingResult result, HttpServletRequest request)
throws IOException {
boolean success = editorProcessor.processSaveAction(exampleString,
exampleEntity, result, request);
return success ? getSuccessView(exampleEntity) : VIEW_NAME;
}
}
And my test:
@WebAppConfiguration
public class ExampleControllerTest{
@Mock private EditorProcessor editorProcessor;
@Mock private IdEditorFactory idEditorFactory;
@InjectMocks private ExampleController exampleController;
private MockMvc mockMvc;
@Before
public void setUp() throws Exception {
MockitoAnnotations.initMocks(this);
mockMvc = MockMvcBuilders.standaloneSetup(exampleController).build();
WebDataBinder webDataBinder = new WebDataBinder(ExampleEntity.class);
webDataBinder.registerCustomEditor(ExampleEntity.class, idEditorFactory.createEditor(ExampleEntity.class));
}
@Test
public void shouldProcessSaveAction() throws Exception {
// given
BindingResult result = mock(BindingResult.class);
ExampleEntity exampleEntity = mock(ExampleEntity.class);
HttpServletRequest httpServletRequest = mock(HttpServletRequest.class);
given(editorProcessor.processSaveAction("confirmed", exampleEntity, result, httpServletRequest)).willReturn(true);
// when
ResultActions perform = mockMvc.perform(post("/").sessionAttr("exampleEntity", exampleEntity)
.param("id", "123456"
.param("action","save"));
// then
perform.andDo(print())
.andExpect(status().isOk());
}
}
I want to somehow mock getExampleEntity()
so that every time I perform a POST with parameter "id", I receive a mocked object ("exampleEntity") for the test.
I could introduce @Binding
to the test, but then I would have to mock many levels of methods (like initBinder -> idEditoryFactory-> editor -> hibernateTemplate and so on) only to get an entity from some source (for example, a database).
回答1:
You can pass in the required @ModelAttribute
object with the .flashAttr()
method like so:
mockMvc.perform(post("/")
.param("id", "123456")
.param("action","save")
.flashAttr("exampleEntity", new ExampleEntity()));
回答2:
First, test code shouldn't change our develop code. @ModeleAttribute will be mount from your param attribute,so .param() is enough. Below is my demo:
@Test
public void registerUser() throws Exception {
System.out.println("hello......."+rob.toString());
RequestBuilder request = post("/register.html")
.param("username", rob.getUsername())
.param("password", rob.getPassword())
.param("firstName",rob.getFirstName())
.param("lastName",rob.getLastName())
.param("email", rob.getEmail())
.with(csrf());
mvc
.perform(request)
.andDo(MockMvcResultHandlers.print())
.andExpect(redirectedUrl("/"));
}
Then is my Controller.
@Controller
public class LoginController
{
@Autowired
private UserService userService;
@RequestMapping(value = "/remove", method = RequestMethod.GET)
public String removeById(@RequestParam("userid")int id,RedirectAttributes attr)
{
attr.addFlashAttribute("message","remove!!!");
attr.addAttribute("mess","remove ");
return "redirect:/userlist.html";
}
@RequestMapping(value = "/register", method = RequestMethod.POST)
public String register(@ModelAttribute("user")User user, ModelMap model)
{
System.out.println("register "+user.toString());
boolean result = userService.add(user);
model.addAttribute("message","add "+(result?"successed":"failed")+"!!!");
return "/";
}
}
This can submit right user object to the public String register(@ModelAttribute("user")User user, ModelMap model).
来源:https://stackoverflow.com/questions/27483064/modelattribute-controller-spring-mvc-mocking