Integration testing: Many-to-one relationships with select-fields

This post is an entry in my ongoing series about web integration testing with Jetty. See post 1, 2 and 3 in the series for more information.

I often find that a web interface needs to let a user select one of a list of objects as a relation to the object he is editing. This is the basic and simple way of dealing with many-to-one relationships. However, most web frameworks don’t make this as easy or well-documented as it should be. In this post, I will describe how to make a select-field with Spring-MVC and FreeMarker.

As always, I will start with a test:

Before we start: Lets do some unit testing

The test we’re working on requires quite advanced behavior from the Categories. Even though integration testing with Jetty is fast, it’s not comparable to real unit tests. To make sure that we don’t waste time testing things in the wrong place, let’s write some unit tests for the category class:

Getting the test to pass requires a bit of logic in Category.setParent. See the companion source code if you’re curious about it.

With the basic behavior in place, it is time to start tackling the web interface. I will ignore null parent values for now. This means that the first iteration of the views will often fail horribly if you try and click around and look at them with a web browser. However, getting these early successes allows us to have visible progress.

Spring-MVC has @spring.formSingleSelect FreeMarker macro. Sadly, I have not found this to be workable when the options are a list of objects. We’re on our own. I will start with the edit.ftl view:

[TODO: Better name for parentOptions?]

In particular, notice that I use the categoryOption.id as the <option> value, and the categoryOption.name as the text. In order for this to work, the name “parentOptions” must be set in the model. This is done in CategoryController. SimpleFormView has a method that is intended just for this:

Now, the view is displayed. But the update doesn’t work correctly. We get a conversion error with Spring, as we haven’t said how we convert from the integers returned in the form to the Category parameter for setParent. Again, Spring MVC’s SimpleFormController has a method for this:

[TODO: Check this for errors, especially on POST versus GET requests. When will we see these problems?]

Shazam! Updates work.

Dealing with null values

If you start the web server and start looking at the web pages, you will notice that null-values are not handled correctly. First: There is not value in the list to select if you want to set the parent property to null, and second, if the property is already null, the first item on the list is selected instead. Here is a test that illustrates what we want to have happen when dealing with null values:

The test will fail because there is no select option with the text “”. The easiest way of dealing with null values is to have an item in the list that can be used for this. There are a few different approaches – the one I have ended up using is to add an actual “null” to the end of the parentOptions:

This requires a change in the view as well. The new code is rather ugly [TODO: Anyone knows how to make it prettier?]:

The first part of the test, displaying the form will now work. But on the update, we will get a NumberFormatException in the controller as we attempt to convert “” to a Long. The cure is simple enough: Make the PropertyEditor for Categories advanced enough to deal with null values and empty strings. The code is trivial, but if you’re interested, you can take a look at the companion source code.

Conclusion?

I have discussed how to display and edit many-to-one relationships with form select lists using Spring-MVC and FreeMarker. At this point in time, a question presents itself: To what extent are our tests representative of what we will see when we take the code into production? As it turns out, Hibernate has a few nice surprises in stock for us. These will be the subject of the next post in this series.

About Johannes Brodwall

Johannes is Principal Software Engineer in SopraSteria. In his spare time he likes to coach teams and developers on better coding, collaboration, planning and product understanding.
This entry was posted in Java, Software Development. Bookmark the permalink.
  • Wagner O .Wutzke

    Very Nice Post!

    it has helped me a lot!

    Thanks!

  • Wagner O .Wutzke

    Very Nice Post!

    it has helped me a lot!

    Thanks!

  • Ramesh

    Fantastic. Saved me days of research. Thanks a lot for making it so simple