Git Product home page Git Product logo

spring-mvc-test-utils's Introduction

Gitpod ready-to-code

Spring MVC Test utils

Maven Central Build Status codecov

Codacy Badge Language grade: Java Dependabot Status

Test library aimed to ease Spring MVC form validation tests. Easily post an entire form to a given url.

See MockMvcRequestBuilderUtils

More details here: blog.florianlopes.io

How to use?

Add this dependency to your pom.xml file:

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

Note: since version 3.0.0, Java 8 is no longer supported, Java 11 is the minimum supported version.

MockMvcRequestBuilderUtils.postForm("/url", formObject);

Example:

@Test
public void testSimpleFields() throws Exception {
    final MockHttpServletRequestBuilder mockHttpServletRequestBuilder = MockMvcRequestBuilderUtils.postForm("/test",
            new AddUserForm("John", "Doe", null, new Address(1, "Street", 5222, "New York")));
    final MockHttpServletRequest request = mockHttpServletRequestBuilder.buildRequest(this.servletContext);

    assertEquals("John", request.getParameter("firstName"));
    assertEquals("New York", request.getParameter("address.city"));
}

Usage with MockMvc:

final AddUserForm addUserForm = new AddUserForm("John", "Doe", null, new Address(1, "Street", 5222, "New York")));

mockMvc.perform(MockMvcRequestBuilderUtils.postForm("/users", addUserForm))
		.andExpect(MockMvcResultMatchers.model().hasNoErrors());

Using with() syntax (FormRequestPostProcessor):

final AddUserForm addUserForm = new AddUserForm("John", "Doe", null, new Address(1, "Street", 5222, "New York")));

// POST
mockMvc.perform(post("/users").with(MockMvcRequestBuilderUtils.form(addUserForm)))
		.andExpect(MockMvcResultMatchers.model().hasNoErrors());

// GET
mockMvc.perform(get("/users").with(MockMvcRequestBuilderUtils.form(addUserForm)))
		.andExpect(MockMvcResultMatchers.model().hasNoErrors());
		
// PUT
mockMvc.perform(put("/users").with(MockMvcRequestBuilderUtils.form(addUserForm)))
		.andExpect(MockMvcResultMatchers.model().hasNoErrors());

Register property editor(s)

This tool relies on default Spring's property editors (see https://github.com/spring-projects/spring-framework/blob/master/spring-beans/src/main/java/org/springframework/beans/PropertyEditorRegistrySupport.java#L200).

If you want to override one of those registered by default, simple use the MockMvcRequestBuilderUtils.registerPropertyEditor(...) method:

MockMvcRequestBuilderUtils.registerPropertyEditor(LocalDate.class, new CustomLocalDatePropertyEditor("dd/MM/yyyy"));

final AddUserForm addUserForm = new AddUserForm("John", "Doe", LocalDate.now(), null);
final MockHttpServletRequestBuilder mockHttpServletRequestBuilder = MockMvcRequestBuilderUtils.postForm(POST_FORM_URL, addUserForm);

MockHttpServletRequest request = mockHttpServletRequestBuilder.buildRequest(this.servletContext);
assertEquals(LocalDate.now().format(DateTimeFormatter.ofPattern("dd/MM/yyyy")), request.getParameter("birthDate"));

Limitations and restrictions

This helper utility handles your form objects using the Java Reflection API. This implies some restrictions in the usage within your test cases:

  • As long as you use simple, common Java types like String, etc, the mocked HTTPServletRequest should not fail to be processed by data binding.

  • You can always provide a custom property editor (see above).

  • Converting data using classes from the Java Collection API is supported since version 1.0.0. The parameters will follow the convention name[index] = value.

    • Currently, no multidimensional collections (like array of arrays) are supported.
  • Converting data using classes from the Java Map API is supported in a simple manner since version 1.1.0. The parameters will follow the convention name[key] = value.

    • Currently, no map of maps is supported, only simple datatypes with key and value easily transformable to a String.
  • As a last resort, your properties will be converted using the toString() method of the member object under the name of the object.

Contributing

Feel free to contribute using this guide:

  1. Fork this project
  2. Clone your forked repository git clone [email protected]:{your-username}/spring-mvc-test-utils.git
  3. Add a new remote pointing to the original repository git remote add upstream [email protected]:flopes/spring-mvc-test-utils.git
  4. Create a new branch for your feature git branch -b my-feature
  5. Commit your changes (and squash them if necessary using git rebase -i or git add -p)
  6. Pull the latest changes from the original repository git checkout master && git pull --rebase upstream master
  7. Rebase master branch with your feature git checkout my-feature && git rebase master Solve any existing conflicts
  8. Push your changes and create a PR on GitHub git push -u origin my-feature Go to the original repository and create a new PR with comments.

spring-mvc-test-utils's People

Contributors

anthonyrichir avatar codacy-badger avatar dependabot-preview[bot] avatar dependabot[bot] avatar f-lopes avatar jkancel avatar lgtm-com[bot] avatar poikilotherm avatar schosin avatar singingbush avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar

spring-mvc-test-utils's Issues

Support multidimensional arrays and maps

Dear @f-lopes,

the addition of support for Map types in #3 is great! In future forms, I will need to test with multidimensional arrays and maps (Array of Arrays, Map of Maps or even more dimensions).

Would you agree that adding support for them would respond to a common pattern of data usage? (At least I know this concept is heavily used within the PHP/Python/Perl world...)

Cheers,
Poikilotherm

Exclude static and transient fields from form fields by default

Hello,

after introducing a Comparator constant to a model class, we're running into issues with certain fields in that comparator not being accessible to reflection. After some digging I found out that this library includes both static and transient fields in the generated form data.

Since most libraries with similar functionality (e.g. JSON Libraries) don't include such fields, I would like to suggest to exclude static and transient fields either alltogether or as a default, but configurable behaviour.

The code change would probably fit into getAllNonSyntheticFields to also exclude aforementioned fields. I would be happy to provide a pull request if there's any interest.

Greetings,
schosins

update for Spring Boot 2.6

for some reason it seems this isn't working with Spring Boot 2.6 and Java 17. Perhaps worth updating spring dependencies

[3.1.0] fails to find handler type and method

I've tried using spring-mvc-test-utils v3.1.0 and found that both:

MockMvcRequestBuilderUtils.postForm("/myapp/path", formObject)

and

MockMvcRequestBuilders.post("/myapp/path").with(MockMvcRequestBuilderUtils.form(formObject))

fail to map to the handler that deals with "/myapp/path". Not sure if it's related but my controller has @RequestMapping("/myapp") on the class and @PostMapping({"/path"}) on the method. Also, the pojo in question uses lombok a bit like this:

@Data
@Builder(setterPrefix = "with")
@NoArgsConstructor
@AllArgsConstructor
public class User {

    @NonNull
    private String emailAddress;

    @Nullable
    private String name;

    private Long level;
}

breaks tests when run from maven

When I run the tests on our CI, the maven runs them and jacoco probably injects some garbage to the objects. The builder then picks it up and adds it to the request, which causes the validations to stop form processing and ultimately, the test fails.

20:09:22.477 [main           ] DEBUG      i.f.s.t.w.s.r.MockMvcRequestBuilderUtils:	Adding form field ($jacocoData=[Z@212beaa6) to HTTP request parameters 

I'm not completely sure where to report this, but the first time I've seen this is with your lib.

Dependencies

output from maven effective pom:

      <dependency>
        <groupId>io.florianlopes</groupId>
        <artifactId>spring-mvc-test-utils</artifactId>
        <version>2.2.0</version>
        <scope>test</scope>
      </dependency>
      <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot</artifactId>
        <version>2.2.0.M1</version>
      </dependency>
      <dependency>
        <groupId>junit</groupId>
        <artifactId>junit</artifactId>
        <version>4.12</version>
      </dependency>

      <plugin>
        <artifactId>maven-surefire-plugin</artifactId>
        <version>2.22.1</version>
        <executions>
          <execution>
            <id>default-test</id>
            <phase>test</phase>
            <goals>
              <goal>test</goal>
            </goals>
            <configuration>
              <systemPropertyVariables>
                <java.util.logging.config.class>com.cogvio.configuration.JavaUtilLoggingConfig</java.util.logging.config.class>
              </systemPropertyVariables>
            </configuration>
          </execution>
        </executions>
        <dependencies>
          <dependency>
            <groupId>org.apache.maven.surefire</groupId>
            <artifactId>surefire-junit4</artifactId>
            <version>2.22.1</version>
            <scope>compile</scope>
          </dependency>
        </dependencies>
        <configuration>
          <systemPropertyVariables>
            <java.util.logging.config.class>com.cogvio.configuration.JavaUtilLoggingConfig</java.util.logging.config.class>
          </systemPropertyVariables>
        </configuration>
      </plugin>

      <plugin>
        <groupId>org.jacoco</groupId>
        <artifactId>jacoco-maven-plugin</artifactId>
        <version>0.8.1</version>
        <executions>
          <execution>
            <goals>
              <goal>prepare-agent</goal>
            </goals>
          </execution>
          <execution>
            <id>generate-code-coverage-report</id>
            <phase>test</phase>
            <goals>
              <goal>report</goal>
            </goals>
          </execution>
        </executions>
      </plugin>

Support for multipart requests

Hi @f-lopes ,
it is very common to send files together with a form. It would be nice to add full support for multipart requests or at least set some methods to public so that the main functionality can be accessed.

Kind regards,
Stefan

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.