spring 通过 MockMVC 测试表单帖子

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/36568518/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-08 01:02:42  来源:igfitidea点击:

Testing Form posts through MockMVC

springform-data

提问by Mathijs Segers

I'm writing tests to verify that I can do a generic form post to our API.

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

I've also added quite some debugging, but I noticed that the data posted by an actual form; (Postman / AngularJS or w/e) Differs from doing a mockMVC test like:

我还添加了一些调试,但我注意到数据是由实际表单发布的;(邮递员/ 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();

The config is exactly the same as the config running in production, and such. However When my interceptor logs the content, in real test (not mockMVC) the content is formatted like "someparam1=somevalue&etc=encore"

该配置与生产中运行的配置完全相同,等等。然而,当我的拦截器记录内容时,在实际测试(不是模拟MVC)中,内容的格式类似于“someparam1=somevalue&etc=encore”

When I print the mockMVC content I actually seem to have no content, but there are Params in the request, I assume they're added like GET parameters.

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

Anyone know how to properly test this? I came upon this issue since it seems like our form posts don't seem to be parsed by Spring even though we have the FormHttpMessageConverter added to the servlet context.

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

回答by Bastian Voigt

If you have Apache HTTPComponents HttpClient on your classpath, you can do it like this:

如果您的类路径上有 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")
            )))));

If you don't have HttpClient, you can do it with a simple helper method that constructs the urlencoded form entity:

如果您没有 HttpClient,您可以使用一个简单的辅助方法来构建 urlencoded 表单实体:

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

With this helper function:

使用这个辅助函数:

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

回答by Florian Lopes

You could also use this small library I created: https://github.com/f-lopes/spring-mvc-test-utils/.

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

Add dependency in pom.xml:

在 pom.xml 中添加依赖:

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

Use it with MockMvc:

与 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"));

This library simply adds the parameters to the MockMvc request, according to the form object.

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

Here is a detailed tutorial I wrote: https://blog.florianlopes.io/tool-for-spring-mockmvcrequestbuilder-forms-tests/

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

回答by HymanMahoney

Here is a Kotlin SpringBoot example:

这是一个 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)
  }

}