Create an account

Very important

  • To access the important data of the forums, you must be active in each forum and especially in the leaks and database leaks section, send data and after sending the data and activity, data and important content will be opened and visible for you.
  • You will only see chat messages from people who are at or below your level.
  • More than 500,000 database leaks and millions of account leaks are waiting for you, so access and view with more activity.
  • Many important data are inactive and inaccessible for you, so open them with activity. (This will be done automatically)


Thread Rating:
  • 680 Vote(s) - 3.53 Average
  • 1
  • 2
  • 3
  • 4
  • 5
Testing Form posts through MockMVC

#1
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.
Reply

#2
You could also use this small library I created:

[To see links please register here]

.

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:

[To see links please register here]

Reply

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

#4
Here is a Kotlin SpringBoot example:

```kotlin
@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)
}

}
```
Reply

#5
With modern spring (5.3.12) the offered solution didn't work. There seems to be a simple and elegant solution using the [param][1] method in MockHttpServletRequestBuilder:


mockMvc.perform(post("/some/super/secret/url")
.param("someparam1", true)
.param("someparam2", false)
.with(csrf())
).andExpect(status().isOk)


*Note*: As I am using using Spring Security I needed to add

> .with(csrf())

So that the CSRF postProcessor allows my request. If not the Spring security would deny the request to avoid a [Cross Site Request Forgery (CSRF) attack.
][2]


[1]:

[To see links please register here]

...-
[2]:

[To see links please register here]

Reply



Forum Jump:


Users browsing this thread:
1 Guest(s)

©0Day  2016 - 2023 | All Rights Reserved.  Made with    for the community. Connected through