使用闭包

时间:2017-08-21 17:45:59

标签: unit-testing grails closures spock

我有一个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约束是仅在需要时指定?

1 个答案:

答案 0 :(得分:0)

您可以将闭包的委托设置为DetachedCriteria模拟,以对其进行断言。 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)
相关问题