问题
I'm writing tests to verify that I can do a generic form post to our 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:
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"
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.
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.
回答1:
If you have Apache HTTPComponents HttpClient on your classpath, you can do it like this:
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:
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();
}
回答2:
You could also use this small library I created: https://github.com/f-lopes/spring-mvc-test-utils/.
Add dependency in 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.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.
Here is a detailed tutorial I wrote: https://blog.florianlopes.io/tool-for-spring-mockmvcrequestbuilder-forms-tests/
来源:https://stackoverflow.com/questions/36568518/testing-form-posts-through-mockmvc