@ModelAttribute控制器spring-mvc嘲笑

Rem*_*mik 4 unit-testing mocking spring-mvc spring-test-mvc mockmvc

我想测试一个@ModelAttribute用于其方法参数之一的控制器.

public String processSaveAction(@ModelAttribute("exampleEntity") ExampleEntity exampleEntity)
Run Code Online (Sandbox Code Playgroud)

@ModelAttribute方法getExampleEntity是使用@RequestParam:

@ModelAttribute("exampleEntity")
public ExampleEntity getExampleEntity(@RequestParam(value = "id", required = true) ExampleEntity exampleEntity) {
Run Code Online (Sandbox Code Playgroud)

我的控制器WebDataBinder用于调用工厂,该工厂根据参数"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;
    }
}
Run Code Online (Sandbox Code Playgroud)

我的测试:

@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());

    }
}
Run Code Online (Sandbox Code Playgroud)

我想以某种方式模拟,getExampleEntity()以便每次我使用参数"id"执行POST时,我都会收到一个用于测试的模拟对象("exampleEntity").

我可以介绍@Binding测试,但后来我必须模拟许多级别的方法(如initBinder - > idEditoryFactory-> editor - > hibernateTemplate等),只是为了从某个源(例如,数据库)获取实体.

小智 10

您可以@ModelAttribute使用如下.flashAttr()方法传入所需的对象:

mockMvc.perform(post("/")                                                           
    .param("id", "123456")
    .param("action","save")
    .flashAttr("exampleEntity", new ExampleEntity()));
Run Code Online (Sandbox Code Playgroud)


小智 5

首先,测试代码不应该改变我们的开发代码。@ModeleAttribute 将从您的 param 属性挂载,因此 .param() 就足够了。下面是我的演示:

@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("/"));
}
Run Code Online (Sandbox Code Playgroud)

然后是我的控制器。

@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 "/";
    }
}
Run Code Online (Sandbox Code Playgroud)

这可以将正确的用户对象提交给公共字符串寄存器(@ModelAttribute("user")User user, ModelMap 模型)。