使用闭包对 GORM 调用进行单元测试
Unit testing a GORM call with a closure
我有一个 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
只在需要时指定约束?
您可以将闭包的委托设置为 DetachedCriteria 的 Mock 以对其进行断言。 DetachedCriteria 是 gorm 中用于构建查询的主要class。
示例:
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)
我有一个 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
只在需要时指定约束?
您可以将闭包的委托设置为 DetachedCriteria 的 Mock 以对其进行断言。 DetachedCriteria 是 gorm 中用于构建查询的主要class。
示例:
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)