Posts

Testing Grails controller actions that use bindData method and render validation errors as JSON

Let’s assume that we have a controller action in a grails application that updates a user domain instance. We want name and surname to be updateable but login and password shouldn’t be updateble. To achieve that we will use the controller’s bindData() method with whitelisting. The action will be called using ajax so we also want to render JSON with validation errors in response if there were any. So our controller might look like that:

And the example User class might look like that:

Our next step will be unit testing the action. We want to make sure that only the whitelisted fields are copied from parameters (testUpdate) and also that the validation errors are rendered (testUpdateValidationError):

It turns out that those tests won’t pass. But not because of the fact that we have bugs in the code, it’s just that grails doesn’t do enough magic for our controller action to be unit testable out of the box.

First problem is that the bindData() method is not mocked in ControllerUnitTestCase. Fortunately thanks to this stackoverflow response we know how to easily mock it. To make it reusable let’s create a mixin out of it:

Now all that we have to do to make it work is to apply it on our test class and call the mockBindData() method in the setUp() method.

Second problem is that by default the JSON converter doesn’t know how to convert bean validation errors. But that’s easily fixable as well – all we have to do is register validation error marshaller in the testUpdateValidationError test:

After the aforementioned changes our passing test class should look like that:

Testing reusable validation

In the application we are developing, a lot of input validation takes place. Most of the input is validated using Command Objects, which are a breeze to use thanks to Grails’ fantastic way of integrating them. However, in some of our Command Objects, there’s some overlap, most notably in the validation part. For example, we use a CreateCustomerCommand and a OrderProductCommand, which both have a ‘zipcode’ field, which, in our case, matches the regular expression [0-9]{4}[a-zA-Z]{2}. Since we don’t want to duplicate this regular expression, we need to come up with a solution to be able to reuse this. Read more