【问题标题】:How to set objects while functional testing grails with Spock如何在使用 Spock 对 grails 进行功能测试时设置对象
【发布时间】:2013-06-18 15:09:49
【问题描述】:

我有一个像这样的示例域

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)
        }
    }
}

userHelper 正在由我的resources.groovy 中的以下人员注入

beans = {
    userHelper(UserHelper)
}

当我从浏览器测试我的应用程序时,一切运行良好。但是,在尝试为此编写功能测试时出现异常。

错误提示:Cannot invoke method validatePassword() on null object

所以我假设在我运行我的功能测试用例时没有设置userHelper

我的测试用例如下所示:

 @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
    }
}

更新

控制器:

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
            }
        }
    }
}

问题

  • 如何在运行测试之前在User 域上设置userHelper 属性?
  • 在运行所有功能和集成测试用例之前,如何在 Bootstrap.groovy 中运行我的代码?

【问题讨论】:

  • 您是指return userInstance.userHelper.validatePassword(pwd),还是return userHelper.validatePassword(pwd)
  • 我的意思是return userInstance.userHelper.validatePassword(pwd),据我所知,validation 的第二个参数是正在验证的域类实例

标签: grails groovy spock


【解决方案1】:

您是否尝试过使用defineBeans?由于这是一个单元测试,您必须明确定义 bean。这通常在 JUnit 中是如何完成的

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

您可以在 setup 方法中defineBeans 使其可用于所有测试用例。

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

更新:

似乎在 spock 的情况下,您可以直接在单元测试中注入一个 spring bean(扩展 Specification 的测试)

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

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

【讨论】:

  • 嗯,没用。我在given 部分添加了defineBeans
  • 不幸的是,这对我不起作用。我不断收到无法在空对象上调用 validatePassword 的相同错误。我正在像grails test-app unit:spock 这样运行我的测试用例,我也尝试将它放在功能文件夹中,但没有运气(使用grails test-app functional:spock 运行)
  • @Anthony 我认为您可以在 spock 单元测试中直接注入 bean。看看更新和this question
  • 你可以在setup: 中使用defineBeans 而不是given:
  • @dmahapatro 您指的答案是集成测试,而不是单元测试!这就是他们可以将 bean 注入测试的原因。
【解决方案2】:

尝试使用元类。

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

如果你想要的话,你也可以模拟 userHelper。

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

确保您正在调用 getUserHelper() 并且直接访问私有 userHelper 属性。明确表示可能是个好主意:

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

@dmahapatro 使用defineBeans{...} 的答案是最好的 方式,但我认为它不起作用,因为this grails bug...

将 bean 直接注入测试的另一个建议仅适用于扩展 grails.plugin.spock.IntegrationSpec 的集成测试。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-03-08
    • 2020-08-22
    相关资源
    最近更新 更多