【问题标题】:Unit testing a GORM call with a closure使用闭包对 GORM 调用进行单元测试
【发布时间】:2017-08-21 17:45:59
【问题描述】:

我有一个 Grails 服务,它会像这样执行 where 查询:

List<Car> search(Long makeId = null) {
    Car.where {
        join("make")
        if(makeId) {
            make.id == makeId
        }
    }.findAll()
}

我正在尝试像这样使用 Spock 对其进行单元测试:

def setup() {
    GroovyMock(Car, global: true)
}

void "test search"() {
    when:
        service.search()
    then:
        1 * Car.where {}
}

但是,我似乎找不到测试闭包内容的方法。

我可以通过验证1 * Car.where(_) 来使测试通过,但是我如何才能对闭包的内容做出断言,即调用了join 并且仅在需要时指定了make.id 约束?

【问题讨论】:

  • 我的偏好是测试搜索方法。在规范中,您将设置仅在指定 makeId 时才返回的数据。因此,使用两个“when / then”块,您可以测试提供/不提供 makeId 是否按预期工作。

标签: unit-testing grails closures spock


【解决方案1】:

您可以将闭包的委托设置为 DetachedCriteria 的 Mock 以对其进行断言。 DetachedCriteria 是 gorm 中用于构建查询的主要类。

例子:

given: 'Mocking DetachedCriteria'
DetachedCriteria detachedCriteriaMock = Mock(DetachedCriteria)
and: 'Just to avoid nullPointerException when findAll() call happens on service'
1 * detachedCriteriaMock.iterator() >> [].listIterator()
when:
service.search(1L)
then:
// Capture the argument
1 * Car.where(_) >>  { args ->
    args[0].delegate = detachedCriteriaMock
    args[0].call()

    return detachedCriteriaMock
}

// Join is a method on detached criteria
1 * detachedCriteriaMock.join('make')
// Make is an association, so detachedCriteria uses the methodMissing to find the property.
// In this case, we call the closure setting the delegate to the mock
1 * detachedCriteriaMock.methodMissing('make', _) >> { args ->
    // args[1] is the list of arguments.
    // args[1][0] is the closure itself passed to detachedCriteria
    args[1][0].delegate = detachedCriteriaMock
    args[1][0].call()
}
// If id is passed, it must compare (eq method) with value 1
1 * detachedCriteriaMock.eq('id', 1L)

【讨论】:

  • 这对于测试join 调用非常有用,我可以用它来测试make.id 约束吗?
  • 是的!但在这种情况下,您想测试与“make”调用方法的交互。所以你必须使用模拟!我对我的示例代码进行了一些重构。希望对您有所帮助。
  • 它确实有帮助,我知道你在这里做什么,但是用你的代码我得到一个MissingMethodException: No signature of method: groovy.util.Expando.make() is applicable for argument types [_closure stuff]...我错过了什么?
  • 很奇怪。看起来测试代码没有使用 Expando Mock。或者代码正在调用真正的实现,或者您可以尝试将1 * joinCallMock.getProperty('make') &gt;&gt; makeCallMock 更改为1 * joinCallMock.invokeMethod('make', []) &gt;&gt; makeCallMock,因为看起来make 不是属性而是方法。
  • 是的,最后我做了一个集成测试,但仍然非常感谢您的澄清:)
猜你喜欢
  • 2021-11-16
  • 2016-05-03
  • 2013-10-15
  • 1970-01-01
  • 2014-05-11
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2022-12-10
相关资源
最近更新 更多