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.
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
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.
Related
I'm working on a servlet to perform some logic specific to a resourceType in sling and set information to the request to be accessible via the jsp then handing off the request to the jsp similarly to the first solution provided in this answer.
Here's some example code to represent my situation:
#SlingServlet(
resourceTypes="myapp/components/mycomponent",
methods="GET",
extensions={"html"}
)
...
#Reference
private ServletResolver serlvetResolver;
protected void doGet(....) {
setPropertiesToRequest();
Servlet servlet = servletResolver.resolveServlet(resource, "....jsp");
servlet.service(slingRequest, slingResponse);
clearPropertiesFromRequest();
}
Because of this, I've noticed that I've lost sling's selector handling (I've had to roll my own simpler version to determine which jsp to render. Full featured sling selector handling is described in more detail here). I wanted to reach out to the stack overflow community and ask what else I may be missing out on by depriving the default get handler of the request. I've scanned through the source code but I think there may be more going on.
Secondly, I'd be interested in thoughts on how and where this approach may impact performance of the request resolution.
Thanks, Thomas
Processing the business logic in Java and delegating to scripts for rendering sounds like a job for the recently released Sling Models. Using that should remove the need to implement your own handling of selectors, as those won't affect the model selection, only the rendering scripts.
Not sure what you are trying to achieve here, but the main problem seems to me that your SlingServlet handles the html extension and by itself does not have selectors to filter a bit more. Thus it of course intercepts all the requests to your component. Then you have to take care of the selectors again to be able to choose the correct JSP.
The question is, why do you use a SlingServlet for it when you anyway do the rendering by JSP?
Can't you implement your logic in the JSP or better in a bean referenced in the JSP?
In our company we use our custom tag that takes care of this, but there are public frameworks available from other Adobe Partner:
https://github.com/Cognifide/Slice
http://neba.io/index.html
I am not really femiliar with java web tchnologies.
I am using spring mvc with apache tiles. Now I desire to create a user control (user control like in asp.net).
For example, I am going to use many times in specific html pattern (like address chooser that uses cascading drop downs and ajax calls).
What is the best thecnology/framework that will allow me create user controls and will work good with spring mvc and tiles?
You can have something that helps you to reuse some code, but in the end it is nothing more like a (more or less intelligent) snippets. (Dave Newton already explaind in his comment, that jsp are action based and not component oriented)
It is called custom tags: tag or tagx.
And good example how to use tagx files and jspx files (the x is important) works together can be found in a spring roo project.
#See http://docs.oracle.com/javaee/5/tutorial/doc/bnalk.html -- may not so good example but it should be complete
This is a follow-on to my question Spring Web MVC - validate individual request params.
I've figured out how to invoke the Spring Validator on domain objects that have been created from my inputs and how to have that validator honor the JSR-303 annotations on my classes themselves. The part I can't figure out is where in my code to perform this validation. The obvious approach is to do it in the controller and return a different model and view if there's a validation failure.
But I also have a service layer which sometimes gets calls to create/update objects from input sources other than the web controller. So it's tempting to implement validation there, but the only obvious way I can think of to report a failure is throw an exception. I see Spring provides BindException but the Javadoc also basically says not to use it in application code.
What is the common/recommended practice here?
I think the answer is both.
Controllers are associated with views. You don't want the validation to disappear if you change view technologies.
Services should assume that no one is safe and validate all incoming parameters.
Other answers are all good, I'll just state one important rule:
Each subsystem/layer should validate its input, no matter where it comes from.
When you encapsule the validation logic inside of a ValidationService you can use it inside your controllers and services. As you want the user to interact with the input and to correct invalid information you should be able to display validation problems in your web view.
Sometimes you might have data (CommandObjects, Forms) which is not directly visible in the service layer and then the validation should be done in the controller which then passes the information into the service layer.
When you design your application you should think about the interaction between each layer. Mixinig validation logic into every layer might not be needed. Think about how data gets into your system. If controllers are your main entry point you can perfectly place it there since no data gets into your services without passing the validation.
At least you should validate inputs at the service layer, in order to guarantee correctness. Additionally you can do validations further up to get better usability, etc. if needed.
Lately I've been running into the same issue with my Spring MVC applications over and over again, and I'm trying to come up with a long term solution.
The problem is that in a standard Spring 3 controller, you add model objects, you specify the view name (either inline or from some injected field) and return. The problem I've run into is that if you have a request that returns a page with a person, and their pets you have something like (not compilable, psuedo):
#RequestMapping( value="personOverview", method="GET" )
public String getPersonOverview(model) {
model.add(personRepo.getPerson( theName ));
model.add(petRepo.getPetsForPerson( thePerson ));
return "personOverviewViewName";
}
Now, in your view you will be able to render all of this information. However, the issue arises when someone updates the "pets" for the person, and you just want to re-render the part of the page that shows the pets.
Not only do you need to rewrite the rendering logic in a JSP fragment or in JavaScript, but also you will need to duplicate the controller code for each portion of the getPersonOverview method. If you were to break the controller methods up into smaller chunks, then you will not be able to render the full page, but will have to render each chunk with a separate request.
In a normal ModelViewController pattern, the solution to this is that the view has access to the model, but in Spring MVC the model is in Java and lies behind the request layer, so you need to build request handlers for each model object.
I know this question may seem a bit abstract, but what I'm looking for is patterns or principles that can be used to allow me to build full pages with many model objects, but also be able to update portions of the page with ajax without duplication.
Not used it myself, but have you considered Tiles?
I'm working on some user related tasks for a website. For cases when the person is registering or editing a user, they fill out a form and the request is handled in a servlet. At the moment, the servlet is taking all the request parameters and building a User object from them, like this:
User toRegister = new User(request.getParameter("name"),
request.getParameter("lastName"));
There's more parameters but you get the point.
So this sort of code is being reused in a bunch of different servlets (registering, admin adding user, user updating self, admin updating others etc) and it's kinda ugly, so I wanted to clean it up. The two alternatives I could think of were a constructor that takes the request object or a static method in the User class to create and return a new User based on the request.
It's not much of a question since I know they would both work but I couldn't find any sort of best practices for this situation. Should I keep to handling the requests individually in the servlets in case the forms change or should I implement one of the above methods?
DON'T add a c'tor that takes a Request as an argument. You only couple your User class to the Servlet API this way.
Instead use a Web Framework as #skaffman suggests. There are many of these, and it will make your life easier.
EDIT: If you refuse to learn a new framework you can at least use BeanUtils of some similar framework to do the data binding only. I do recommend the Web Framework option though.
Instead of coding all the business logic in the servlet, why dont you use basic MVC framework. Using a framework will make your coding and testing a lot easier.