Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to mock springSecurityService in an unit test

I am unit testing a Grails controller method that internally creates an user instance. User domain class uses the springSecurityService of the Spring Security plugin to encode the password before inserting it into the database.

Is there a way to mock that springSecurityService from my unit test in order to get rid of that error?

 Failure:  Create new individual member(MemberControllerSpec)
|  java.lang.NullPointerException: Cannot invoke method encodePassword() on null object

Please find my unit test below.

@TestMixin(HibernateTestMixin)
@TestFor(MemberController)
@Domain([User, IndividualPerson])
class MemberControllerSpec extends Specification {

void "Create new individual member"() {

    given:
    UserDetailsService userDetailsService = Mock(UserDetailsService)
    controller.userDetailsService = userDetailsService

    def command = new IndividualPersonCommand()
    command.username = '[email protected]'
    command.password = 'What ever'
    command.firstname = 'Scott'
    command.lastname = 'Tiger'
    command.dob = new Date()
    command.email = command.username
    command.phone = '89348'
    command.street = 'A Street'
    command.housenumber = '2'
    command.postcode = '8888'
    command.city = 'A City'

    when:
    request.method = 'POST'
    controller.updateIndividualInstance(command)

    then:
    view == 'createInstance'

    and:
    1 * userDetailsService.loadUserByUsername(command.username) >> null

    and:
    IndividualPerson.count() == 1

    and:
    User.count() == 1

    cleanup:
    IndividualPerson.findAll()*.delete()
    User.findAll()*.delete()
}
}
like image 662
saw303 Avatar asked Sep 03 '15 11:09

saw303


2 Answers

One way to mock a service is to use Groovy's MetaClass

import grails.test.mixin.Mock
import grails.plugin.springsecurity.SpringSecurityService

...
@Mock(SpringSecurityService)
class MemberControllerSpec extends Specification {

    def setupSpec() {
        SpringSecurityService.metaClass.encodePassword = { password -> password }
    }

    def cleanupSpec() {
        SpringSecurityService.metaClass = null
    }
....

In this example, the call to SpringSecurityService.encodePassword() will simply return the password in plain text.

An approach using Mocks is discussed here.

like image 122
Emmanuel Rosa Avatar answered Nov 06 '22 08:11

Emmanuel Rosa


You can to use this code to encode password in User:

def beforeInsert() {
    encodePassword()
}

def beforeUpdate() {
    if (isDirty('password')) {
        encodePassword()
    }
}

protected void encodePassword() {
    password = springSecurityService?.passwordEncoder ? springSecurityService.encodePassword(password) : password
}

When springSecurityService is null, encodePassword is not called and NPE is not raised

like image 2
AA. Avatar answered Nov 06 '22 10:11

AA.