Grails 2.2.4/Spock:存根服务交互:为什么被拒绝的值被忽略?
Grails 2.2.4/Spock: Stubbed Service Interaction: Why is a rejected value being ignored?
给定一个带有注入服务的简单域,用于在约束内执行特定验证,例如:
package org.example.domain
class Ninja {
String name
String sensei
String village
def ninjaService
static transients = ['ninjaService']
static constraints = {
....
village nullable:true, validator:{ val, obj, errors ->
obj.ninjaService.validate(obj)
}
}
}
还有一个简单的规范,它对服务行为进行存根,例如:
package org.example.domain
import grails.test.mixin.Mock
import spock.lang.Specification
import grails.test.mixin.TestFor
import org.example.services.NinjaService
@TestFor(Ninja)
class NinjaSpec extends Specification {
def 'Should succeed at validating the village using a stubbed method'() {
given:
def instance = new Ninja(village: 'Leaf')
instance.ninjaService = Mock(NinjaService)
when:
instance.validate(['village'])
then:
1 * instance.ninjaService.validate(instance) >> { final Ninja ninja ->
ninja.errors.rejectValue 'village', 'should.be.an.error', [].toArray(), null
ninja.log.debug "[NINJA SERVICE MOCK] (VALIDATING) 'village' FIRED! ninja.errors['village']?.code: '${ninja.errors['village']?.code}'"
}
and:
instance.errors['village']?.code == 'should.be.an.error'
}
}
然后,instance.errors['village']?.code 为空。
看看:
grails test-app unit:spock -clean -echoOut NinjaSpec
| Compiling 121 source files
| Running 1 spock test... 1 of 1
--Output from Should succeed at validating the village via mock--
2016-02-04 19:51:00.219 [main] grails.app.domain.org.example.domain.Ninja
DEBUG [NINJA SERVICE MOCK] (VALIDATING) 'village' FIRED! ninja.errors['village']?.code: 'should.be.an.error'
| Failure: Should succeed at validating the village via mock(org.example.domain.NinjaSpec)
| Condition not satisfied:
instance.errors['village']?.code == 'should.be.an.error'
| | | | |
| | null null false
| org.grails.datastore.mapping.validation.ValidationErrors: 0 errors
org.example.domain.Ninja : (unsaved)
at org.example.domain.NinjaSpec.Should succeed at validating the village via mock(NinjaSpec.groovy:36)
| Completed 1 Spock test, 1 failed in 2032ms
为什么实例不包含已在存根交互中设置的代码 should.be.an.error?
您似乎没有使用该服务,而是一个模拟服务,因此它可能无法验证任何内容。尝试创建服务实例而不是模拟它。
@PabloPazos 使用 mockFor() 和 createMock() 建议的这个实现非常有效!
def 'Should succeed at validating the village via mock'() {
given:
def instance = new Ninja(village: 'Leaf')
def ninjaServiceMock = mockFor(NinjaService)
ninjaServiceMock.demand.validate { final Ninja ninja ->
ninja.errors.rejectValue 'village', 'should.be.an.error', [].toArray(), null
}
instance.ninjaService = ninjaServiceMock.createMock()
when:
instance.validate(['village'])
then:
instance.errors['village']?.code == 'should.be.an.error'
}
不过,我还是不明白为什么 Spock 存根服务不起作用。
给定一个带有注入服务的简单域,用于在约束内执行特定验证,例如:
package org.example.domain
class Ninja {
String name
String sensei
String village
def ninjaService
static transients = ['ninjaService']
static constraints = {
....
village nullable:true, validator:{ val, obj, errors ->
obj.ninjaService.validate(obj)
}
}
}
还有一个简单的规范,它对服务行为进行存根,例如:
package org.example.domain
import grails.test.mixin.Mock
import spock.lang.Specification
import grails.test.mixin.TestFor
import org.example.services.NinjaService
@TestFor(Ninja)
class NinjaSpec extends Specification {
def 'Should succeed at validating the village using a stubbed method'() {
given:
def instance = new Ninja(village: 'Leaf')
instance.ninjaService = Mock(NinjaService)
when:
instance.validate(['village'])
then:
1 * instance.ninjaService.validate(instance) >> { final Ninja ninja ->
ninja.errors.rejectValue 'village', 'should.be.an.error', [].toArray(), null
ninja.log.debug "[NINJA SERVICE MOCK] (VALIDATING) 'village' FIRED! ninja.errors['village']?.code: '${ninja.errors['village']?.code}'"
}
and:
instance.errors['village']?.code == 'should.be.an.error'
}
}
然后,instance.errors['village']?.code 为空。 看看:
grails test-app unit:spock -clean -echoOut NinjaSpec
| Compiling 121 source files
| Running 1 spock test... 1 of 1
--Output from Should succeed at validating the village via mock--
2016-02-04 19:51:00.219 [main] grails.app.domain.org.example.domain.Ninja
DEBUG [NINJA SERVICE MOCK] (VALIDATING) 'village' FIRED! ninja.errors['village']?.code: 'should.be.an.error'
| Failure: Should succeed at validating the village via mock(org.example.domain.NinjaSpec)
| Condition not satisfied:
instance.errors['village']?.code == 'should.be.an.error'
| | | | |
| | null null false
| org.grails.datastore.mapping.validation.ValidationErrors: 0 errors
org.example.domain.Ninja : (unsaved)
at org.example.domain.NinjaSpec.Should succeed at validating the village via mock(NinjaSpec.groovy:36)
| Completed 1 Spock test, 1 failed in 2032ms
为什么实例不包含已在存根交互中设置的代码 should.be.an.error?
您似乎没有使用该服务,而是一个模拟服务,因此它可能无法验证任何内容。尝试创建服务实例而不是模拟它。
@PabloPazos 使用 mockFor() 和 createMock() 建议的这个实现非常有效!
def 'Should succeed at validating the village via mock'() {
given:
def instance = new Ninja(village: 'Leaf')
def ninjaServiceMock = mockFor(NinjaService)
ninjaServiceMock.demand.validate { final Ninja ninja ->
ninja.errors.rejectValue 'village', 'should.be.an.error', [].toArray(), null
}
instance.ninjaService = ninjaServiceMock.createMock()
when:
instance.validate(['village'])
then:
instance.errors['village']?.code == 'should.be.an.error'
}
不过,我还是不明白为什么 Spock 存根服务不起作用。