Search code examples
unit-testinggrailsspring-security

Grails how to perform unit test on exceptions


I am trying to test that the account expired exception.

def authfail() {
    String msg = ''
    def exception = session[WebAttributes.AUTHENTICATION_EXCEPTION]

//        println("print exception: ${exception} | ${session} | ${springSecurityService.getCurrentUser()}")
    if (exception) {
        if (exception instanceof AccountExpiredException) {
            msg = message(code: 'springSecurity.errors.login.expired')
        }
        else if (exception instanceof CredentialsExpiredException) {
            msg = message(code: 'springSecurity.errors.login.passwordExpired')
        }
        else if (exception instanceof DisabledException) {
            msg = message(code: 'springSecurity.errors.login.disabled')
        }
        else {
            msg = message(code: 'springSecurity.errors.login.fail')
        }
    }

    if (springSecurityService.isAjax(request)) {
        render([error: msg] as JSON)
    }
    else {
        flash.message = msg
        redirect action: 'auth', params: params
    }
}

I tried writing the test case above before realising i was stuck as I have no idea how to trigger an expired login so that the unit test criteria of having the AccountExceptionExpired exception thrown be fulfilled.

void "test authFail"() {

when:
    session."${WebAttributes.AUTHENTICATION_EXCEPTION}" = new AccountExpiredException( 'This account has expired' )
    def logexp = controller.authfail()
then:
    logexp == 'springSecurity.errors.login.expired'
when:
    session."${WebAttributes.AUTHENTICATION_EXCEPTION}" = new CredentialsExpiredException( 'This credentials have expired' )
    def passexp = controller.authfail()
then:
    passexp == 'springSecurity.errors.login.passwordExpired'
when:
    session."${WebAttributes.AUTHENTICATION_EXCEPTION}" = new DisabledException( 'The account is disabled' )
    def logdis = controller.authfail()
then:
    logdis == 'springSecurity.errors.login.disabled'
when:
    session."${WebAttributes.AUTHENTICATION_EXCEPTION}" = new UnsupportedOperationException( 'Sorry, we were not able to find a user with that username and password.' )
    def logfail = controller.authfail()
then:
    logfail == 'springSecurity.errors.login.fail'
when:
    controller.authfail()
then:
    1 * springSecurityService.isAjax( _ ) >> true
    controller.response.json == [error :'springSecurity.errors.login.fail']

    }
}

Solution

  • The following will test the majority of your method:

    import grails.plugin.springsecurity.SpringSecurityService
    import grails.test.mixin.TestFor
    import org.springframework.security.authentication.AccountExpiredException
    import org.springframework.security.authentication.CredentialsExpiredException
    import org.springframework.security.authentication.DisabledException
    import org.springframework.security.web.WebAttributes
    import spock.lang.Specification
    
    @TestFor(YourController)
    class YourControllerSpec extends Specification {
    
    def springSecurityService = Mock( SpringSecurityService )
    
    void setup() {
        controller.springSecurityService = springSecurityService
    }
    
    void "test authFail"() {
        given:
            session."${WebAttributes.AUTHENTICATION_EXCEPTION}" = new AccountExpiredException( 'This account has expired' )
        when:
            controller.authfail()
        then:
            flash.message == 'springSecurity.errors.login.expired'
        when:
            session."${WebAttributes.AUTHENTICATION_EXCEPTION}" = new CredentialsExpiredException( 'This credentials have expired' )
            controller.authfail()
        then:
            flash.message == 'springSecurity.errors.login.passwordExpired'
        when:
            session."${WebAttributes.AUTHENTICATION_EXCEPTION}" = new DisabledException( 'The account is disabled' )
            controller.authfail()
        then:
            flash.message == 'springSecurity.errors.login.disabled'
        when:
            session."${WebAttributes.AUTHENTICATION_EXCEPTION}" = new UnsupportedOperationException( 'Bad stuff' )
            controller.authfail()
        then:
            flash.message == 'springSecurity.errors.login.fail'
        when:
            controller.authfail()
        then:
            1 * springSecurityService.isAjax( _ ) >> true
            response.json == [error :'springSecurity.errors.login.fail']
    }
    }
    

    The session is just a map to which we add a key of the string constant and a value of the exception. For all tests bar the final one we're falling through to your final else block, in the final test we return true for `isAjax'.