How to set objects while functional testing grails with Spock

房东的猫 提交于 2019-12-31 01:56:12

问题


I've got a sample Domain such as this

class User {
    String username
    String password

    def userHelper

    static contraints = {
        username(nullable: false, blank: false)
        password nullable: false, blank: false, validator: {pwd, userInstance ->
            return userInstance.userHelper.validatePassword(pwd)
        }
    }
}

the userHelper is being injected by the following in my resources.groovy

beans = {
    userHelper(UserHelper)
}

When I test my application from the browser, everything runs fine. However, I get an exception while trying to write functional tests for this.

The error says: Cannot invoke method validatePassword() on null object

So I'm assuming that userHelper is not being set when I run my functional test case.

My test case looks like this:

 @TestFor(UserController)
 @Mock([User])

class UserControllerSpecification extends Specification {


    def "save user" () {
        given:
            request.contentType = "application/json"
            request.JSON = """
                            {user:
                                {
                                    username: "somtething"
                                    password: "something"
                                }
                            }
                        """
        when: 
            controller.save()

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

Update

Controller:

class UserController {
    def userService
    def save() {
        def user = new User(params?.user)
        request.withFormat {
            json {
                if(user.validate())
                  userService.processUser()
                  //do something
                else
                  //do something else
            }
        }
    }
}

Questions

  • How can I set the userHelper property on User domain prior to running my tests?
  • How can I run my code in Bootstrap.groovy prior to running all my functional and integration test cases?

回答1:


Have you tried using defineBeans? Since this is a unit test you have to explicitly define the beans. This how it is normally done in JUnit

defineBeans{
    userHelper(UserHelper){bean ->
        //in case you have other beans defined inside helper
        bean.autowire = true 
    }
}

You can defineBeans in the setup method to make it available for all the test cases.

@Before
void setup(){
    defineBeans{
        userHelper(UserHelper){bean ->
            //in case you have other beans defined inside helper
            bean.autowire = true 
        }
    }
}   

UPDATE:

Seems like in case of spock you can directly inject a spring bean inside a Unit Test (test which extends Specification)

class UserControllerSpecification extends Specification {
    def userHelper //injected here in case of spock

    def "save user" () {
     ................
    }
}



回答2:


Try using the metaClass.

def setup(){
    User.metaClass.getUserHelper = {new UserHelper()}
}

You could also mock userHelper if that's what you want.

def setup(){
    def userHelperMock = Mock(UserHelper)
    userHelperMock.validatePassword(_) >> true
    User.metaClass.getUserHelper = {userHelperMock}
}

Make sure you are calling getUserHelper() and not accessing the private userHelper property directly. It might be a good idea to make that explicit:

password nullable: false, blank: false, validator: {pwd, userInstance ->
    return this.getUserHelper().validatePassword(pwd)
}

@dmahapatro 's answer to use defineBeans{...} is the best way, but I think it's not working because of this grails bug...

The other suggestion to directly inject the bean into the test will only work in an integration test that extends grails.plugin.spock.IntegrationSpec.



来源:https://stackoverflow.com/questions/17172482/how-to-set-objects-while-functional-testing-grails-with-spock

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!