SpaceNet
SpaceNet

Reputation: 193

How can I test a service injected to other service in Grails?

I got an error at calling a service from other service.

| Running 13 unit tests... 1 of 13
| Failure:  test myAction(MyServiceSpec)
2015.05.27/02:17:09  ERROR StackTrace -- Full Stack Trace:
java.lang.NullPointerException: Cannot invoke method saveUserRole() on null object

I made two service as below.

class MyService {
    def userRoleService
    def myAction(){
        def userQuery = User.where{username == "test1"}.get()
        def roleQuery = Role.where{authority == "ROLE_ADMIN"}.get()
        if (userQuery && roleQuery){
            userRoleService.saveUserRole(userQuery, roleQuery)
        }
    }
}

class UserRoleService{
    def saveUserRole(user, role){
        new UserRole(role: role, user:user).save(flush: true)
    }
}

I want to test myAction() of MyService, so I made MyServiceSpec as below.

@TestFor(DatabaseService)
@TestMixin(DomainClassUnitTestMixin)
class MyServiceSpec extends Specification {
    def userRoleService 
    def setup() { }
    def cleanup() { }
    void "test myAction"(){
        setup:
        mockDomain( Role,[ [authority:"ROLE_ADMIN"], [authority:"ROLE_USER"] ] )
        mockDomain( User,[ [username:"test1",password:"1234"] ] )
        mockDomain( UserRole )

        when: "call the action"
        service.myAction()

        then:
        UserRole.count() == 1
    }   
}

This error is caused when userRoleService.saveUserRole(userQuery, roleQuery) is called.

How can I test of myAction() of MyService without error?

----

UPDATE

I changed the Spec Class as below.

@TestFor(DatabaseService)
@TestMixin(DomainClassUnitTestMixin)
class MyServiceSpec extends Specification {
    def setup() { }
    def cleanup() { }
    void "test myAction"(){
        setup:
        mockDomain( Role,[ [authority:"ROLE_ADMIN"], [authority:"ROLE_USER"] ] )
        mockDomain( User,[ [username:"test1",password:"1234"] ] )
        mockDomain( UserRole )
        def userQuery = User.where{username == "test1"}.get()
        def roleQuery = Role.where{authority == "ROLE_ADMIN"}.get()
        def mockUserRoleService = Mock(UserRoleService){
            1 * saveUserRole(userQuery, roleQuery) >> new UserRole(role: roleQuery, user:userQuery).save(flush: true)
        }
        service.userRoleService = mockUserRoleService

        when: "call the action"
        service.myAction()

        then:
        UserRole.count() == 1
    }   
}

The test recognizes the service class, thanks.

But it seems this test case is not good or this program design is not good.

Do you have any suggestion of referctoring this code?

Upvotes: 0

Views: 516

Answers (1)

SpaceNet
SpaceNet

Reputation: 193

Following comments, I changed the Spec Class as below.

@TestFor(DatabaseService)
@TestMixin(DomainClassUnitTestMixin)
class MyServiceSpec extends Specification {
    def setup() { }
    def cleanup() { }
    void "test myAction"(){
        setup:
        mockDomain( Role,[ [authority:"ROLE_ADMIN"], [authority:"ROLE_USER"] ] )
        mockDomain( User,[ [username:"test1",password:"1234"] ] )
        mockDomain( UserRole )
        def userQuery = User.where{username == "test1"}.get()
        def roleQuery = Role.where{authority == "ROLE_ADMIN"}.get()
        def mockUserRoleService = Mock(UserRoleService){
            1 * saveUserRole(userQuery, roleQuery) >> new UserRole(role: roleQuery, user:userQuery).save(flush: true)
        }
        service.userRoleService = mockUserRoleService

        when: "call the action"
        service.myAction()

        then:
        UserRole.count() == 1
    }   
}

The test recognizes the service class, thanks.

But it seems this test case is not good or this program design is not good.

Do you have any suggestion of referctoring this code?

Upvotes: 1

Related Questions