问题
I am working on a Spring Boot app using Thymeleaf & Spring MVC, and I came across a bug in the code where someone had bound the Spring MVC model to 2 different HTML form fields:
<input th:field="*{userModel.name}" type="text" />
<input id="name" th:field="*{userModel.name}" type="hidden" />
This was causing the name field in the model of the controller to get set to a string of comma-separated values. "Steve,Steve" for example. I fixed the problem, but I'm wondering the simplest way to write a regression test for this. There is a Spring MVC testing framework, which I could use as on this blog post, but what I really want to test is the interaction between the rendered template and the controller, not just the controller.
I could use a selenium test, but I recently read this Martin Fowler bliki/article (blikticle?) in which he says:
In particular a common problem is that teams conflate the concepts of end-to-end tests, UI tests, and customer facing tests. These are all orthogonal characteristics.
I think this is a great point. What I would like to write is a UI component (integration?) test, I think. Something smaller than loading up the whole page. Something only testing the form generation and submission.
Another idea I had was that this sort of bug might be best caught through a static-analysis tool, but that's a bit beyond my scope.
In this project, I've realized that the interactions between Spring MVC and the HTML forms are a common place for errors, so it would be nice to have a way to test just these interactions.
EDIT:
Upon further consideration, I think these are the steps I want in my test:
- Select
<form>tag out of a template's thymeleaf template and render it, passing in appropriate data on the model - Possibly programmatically edit the rendered form values (from Java) to simulate JavaScript interactions.
- Generate a browser's http POST request based on rendered form.
- Use whatever Spring uses to convert POST request to the controller's model parameter
- Either call the controller and verify the results, or just assert that the model was created correctly
I think I may able to do #1 with Thymeleaf's fragment selectors or by refactoring my form out into a separate template. #2 I can do easily with JSoup. It's #3 & #4 that I'm not sure how to do. #3 I might be able to write myself maybe, depending on how the HttpServletRequest mocks work. #4 seems like it's gotta be available in Spring somewhere but I'm new to Spring.
UPDATE:
Looking at the WebDataBinder as a possible solution for #4.
回答1:
I think you should test the functionality and to get good path-coverage of the controller calling the controller directly, mocking the underlying services. Then you can test if the model is correctly filled.
You can test a complex template with Thymeleaf-test infrastructure.
However, at the end of the day, everything must work together. This test should be done with selenium, to check the the variable-names match (So your regression). Normally you should only need a few tests for each page. If you have a lot of JS you should test complex JS functionality with buster.js. The htmlunitdriver of selenium is really fast, so I assume that the performance shouldn't be a big issue. But don't test all controller- or service-paths with selenium.
回答2:
A few years later, it looks like you can do now essentially what I wanted using HtmlUnit/SpringMVC Test integration. It will shortcut any calls you make to your controller and use MockMVC instead, without a Servlet Container.
So, you get the advantage of a html-smart client library to wrap the front end like a browser without the overhead of the servlet container and with the ability to mock out whatever you want to under the controller.
https://docs.spring.io/spring/docs/current/spring-framework-reference/testing.html#spring-mvc-test-server-htmlunit
来源:https://stackoverflow.com/questions/24171876/best-way-to-test-thymeleaf-form-spring-mvc-controller-interaction