Unit testing with SpringSecurityUtils

Unit testing controllers is often overlooked in favour of Integration testing simply because of all the services you need to mock out while testing, that is, it's simply easier to do Integration tests when the mocked Domain classes etc. are not as full featured as the real ones. The trouble is unit tests are generally much faster, they don't rely on resources like DB and specify the tests a lot better, you are only testing this bit, not the services.

So it is desirable in many cases to be able to unit test a controller where possible. Spring Security is one place that people get hung up when unit testing. For example if you have controller action that looks something like this:-

Now you control that method however this "fix" comes with a WARNING: when you replace a method this way it stays replaced while the JVM is alive, so if you have functional tests that rely on this method and just use grails test-app to do all tests chances are your functional tests will fail.

To remove your meta programming methods you would have to do something like this in tearDown() :-

Adding bindData() to a Service

Sometimes when you don't want to repeat yourself in controllers you
need to add some support code to a grails Service. If you do this then
you quickly reach the point where you'd really like bindData() to be
available on a Service. JT's blog has a nice little teaser there, but it's not quite the same as having bindData() just being available, so how do you do it?

So what we're looking at here is adding the DynamicMethod BindDynamicMethod to a DynamicMethodInterceptor added to our service class when it's constructed.

More testing Grails Spring Security

One thing I missed in my last article on integration testing with Grails Spring Security plugin was a test to see that you weren't authenticated, or couldn't access the controller method. So I put that test in and was surprised that I could get to the controller! So the Secure controller looked like this:

package com.nerderg.tester

import grails.plugins.springsecurity.Securedclass SecureController {

@Secured(['ROLE_ADMIN']) def index = { render "Secure access only" }}

Of course this is because the test code calls index() directly, missing the security filter. That means you can unit test your annotated controllers function sans security if you want, but it makes it hard to test the security unless you use a web test (WebDriver/Geb).

So what use is the technique I described previously? We'll if you use the SpringSecurityUtil functions you still need to be authenticated. For example if your controller looked like this: