Grails Can't inject service to domain when test with Spock

820 Views Asked by At

When do grails unit test with Spock, can't auto inject a service instance to domain.

Below is my code.

Service:

class HiService {

    public HiService(){
        println "Init HiService," + this.toString()
    }

    def sayHi(String name){
        println "Hi, ${name}"
    }
}

Domain:

class User {

    public User(){
        if (hiService == null){
            println "hiService is null when new User(${name})"
        }
    }

    String name

    def hiService

    def sayHi(){
        println "Before use hiService " + hiService?.toString()
        hiService.sayHi(name)
        println "End use hiService" +  hiService?.toString()
    }
}

TestCase:

@TestFor(HiService)
@Mock([User])
class HiServiceTest extends Specification {

    def "test sayHi"() {

        given:
        def item = new User( name: "kitty").save(validate: false)

        when: "Use service method"
        item.sayHi()

        then : "expect something happen"
        assertEquals(1, 1)
    }
}

The following was console log:

--Output from test sayHi--
Init HiService,test.HiService@530f5e8e
hiService is null when new User(null)
Before use hiService null
| Failure:  test sayHi(test.HiServiceTest)
|  java.lang.NullPointerException: Cannot invoke method sayHi() on null object
 at test.User.sayHi(User.groovy:17)
 at test.HiServiceTest.test sayHi(HiServiceTest.groovy:20)

The service initialized, but can't inject to domain. But when run app directly, service will auto-inject to domain

3

There are 3 best solutions below

0
On BEST ANSWER

If you wan't autowiring it needs to be an integration test. If using Grails 3 then annotate with @Integration, if grails 2 then extend IntegrationSpec.

See: http://docs.grails.org/latest/guide/testing.html#integrationTesting

0
On

@Mock([User, HiService])
class HiServiceTest extends Specification {

    def "test sayHi"() {
        // ....
    }
}

0
On

Since you are writing unit tests, your service will not be autowired. Also as you are unit testing the User class object, you should write the test in UserSpec (instead of UserServceTest; Suffixing Spec is the convention in Spock). Now you can mock the HiService instead like this:

class UserSpec extends Specification {

def "User is able to say hi"() {
    given:
    User user = new User(name: 'bla bla')

    and: "Mock the user service"
    def hiService = Mock(HiService)
    user.hiService = hiService

    when:
    user.sayHi()

    then:
    1 * sayHiService.sayHi(user.name)
}

}