通过MockMVC测试表单帖子

时间:2016-04-12 09:06:12

标签: spring form-data

我正在编写测试以验证我可以在我们的API上发布通用表单。

我还添加了一些调试,但我注意到实际表单发布的数据; (邮差/ AngularJS或w / e)与做模拟MVC测试不同,如:

MvcResult response = mockMvc
            .perform(post("/some/super/secret/url") //
                    .param("someparam1", "somevalue") //
                    .param("someparam2", "somevalue") //                
                    .contentType(MediaType.APPLICATION_FORM_URLENCODED) //
                    .accept(MediaType.APPLICATION_JSON)) //
            .andExpect(status().isOk()) //
            .andReturn();

配置与生产中运行的配置完全相同,等等。然而,当我的拦截器记录内容时,在实际测试(而不是mockMVC)中,内容的格式为" someparam1 = somevalue& etc = encore"

当我打印mockMVC内容时,我实际上似乎没有内容,但请求中有Params,我认为它们像GET参数一样被添加。

任何人都知道如何正确测试这个?我遇到了这个问题,因为看起来我们的表单帖子似乎没有被Spring解析,即使我们已经将FormHttpMessageConverter添加到servlet上下文中。

3 个答案:

答案 0 :(得分:18)

如果你的类路径上有Apache HTTPComponents HttpClient,你可以这样做:

    mockMvc.perform(post("/some/super/secret/url")
            .contentType(MediaType.APPLICATION_FORM_URLENCODED)
            .content(EntityUtils.toString(new UrlEncodedFormEntity(Arrays.asList(
                    new BasicNameValuePair("someparam1", "true"),
                    new BasicNameValuePair("someparam2", "test")
            )))));

如果您没有HttpClient,可以使用构造urlencoded表单实体的简单帮助器方法来实现:

    mockMvc.perform(post("/some/super/secret/url")
            .contentType(MediaType.APPLICATION_FORM_URLENCODED)
            .content(buildUrlEncodedFormEntity(
         "someparam1", "value1", 
         "someparam2", "value2"
    ))));

使用此辅助函数:

private String buildUrlEncodedFormEntity(String... params) {
    if( (params.length % 2) > 0 ) {
       throw new IllegalArgumentException("Need to give an even number of parameters");
    }
    StringBuilder result = new StringBuilder();
    for (int i=0; i<params.length; i+=2) {
        if( i > 0 ) {
            result.append('&');
        }
        try {
            result.
            append(URLEncoder.encode(params[i], StandardCharsets.UTF_8.name())).
            append('=').
            append(URLEncoder.encode(params[i+1], StandardCharsets.UTF_8.name()));
        }
        catch (UnsupportedEncodingException e) {
            throw new RuntimeException(e);
        }
    }
    return result.toString();
 }

答案 1 :(得分:1)

您也可以使用我创建的这个小型库:https://github.com/f-lopes/spring-mvc-test-utils/

在pom.xml中添加依赖项:

<dependency>
    <groupId>io.florianlopes</groupId>
    <artifactId>spring-mvc-test-utils</artifactId>
    <version>1.0.1</version>
    <scope>test</scope>
</dependency>

与MockMvc一起使用:

mockMvc.perform(MockMvcRequestBuilderUtils.postForm("/users", new AddUserForm("John", "Doe", null, new Address(1, "Street", 5222, "New York"))))
    .andExpect(MockMvcResultMatchers.status().isFound())
    .andExpect(MockMvcResultMatchers.redirectedUrl("/users"))
    .andExpect(MockMvcResultMatchers.flash().attribute("message", "success"));

根据表单对象,该库只是将参数添加到MockMvc请求中。

这是我写的详细教程:https://blog.florianlopes.io/tool-for-spring-mockmvcrequestbuilder-forms-tests/

答案 2 :(得分:0)

以下是Kotlin SpringBoot示例:

@RunWith(MockitoJUnitRunner::class)
class ApiFormControllerTest {

  lateinit var mvc: MockMvc

  @InjectMocks
  lateinit var apiFormController: ApiFormController

  @Before
  fun setup() {
    mvc = MockMvcBuilders.standaloneSetup(apiFormController).setControllerAdvice(ExceptionAdvice()).build()
  }

  fun MockHttpServletRequestBuilder.withForm(params: Map<String, String>): MockHttpServletRequestBuilder {
    this.contentType(MediaType.APPLICATION_FORM_URLENCODED)
        .content(
            EntityUtils.toString(
                UrlEncodedFormEntity(
                    params.entries.toList().map { BasicNameValuePair(it.key, it.value) }
                )
            )
        )
    return this
  }

  @Test
  fun canSubmitValidForm() {
    mvc.perform(post("/forms").withForm(mapOf("subject" to "hello")))
        .andExpect(status().isOk)
  }

}