使用@PostConstruct和Spock单元测试的无法测试的grails(2.5.4)服务
问题描述:
我有一项服务,我希望通过@PostConstuct
进行初始化,通过获取Config.groovy
中的一些配置条目。使用@PostConstruct和Spock单元测试的无法测试的grails(2.5.4)服务
我也希望检查这些条目是否已正确配置,并抛出异常,以便发现应用程序配置错误。
在为此服务编写单元测试时,我在Spock中陷入了一个死胡同。
Spock显然调用@PostConstruct
方法,但只能在共享服务实例上执行,然后在测试的实例上执行您测试的任何实例方法。
这具有一个反常的副作用:
我的初始化代码可能是因为我不添加setupSpec
初始化共享实例,或它在受测试的方法失败,因为配置实际上没有设定失败在这种情况下。
这里是我的服务:
package issue
import org.codehaus.groovy.grails.commons.GrailsApplication
import javax.annotation.PostConstruct
class MyService {
GrailsApplication grailsApplication
String property
@PostConstruct
void init() {
println "Initializing... ${this}"
property = grailsApplication.config.myProperty
//Enabling this business sanity check make the service untestable under Spock, because to be able to run, we need to initialize the configuration
// of the shared instance - PostConstruct is only called on the shared instance for some reason.
// But the execution of the method under test will not have the initialized property, because the service being executed is not the shared instance
if (property == "[:]") {
throw new RuntimeException("This property cannot be empty")
}
}
void doSomething() {
println "Executing... ${this}"
println(property.toLowerCase())
}
}
这是我的第一个测试:
package issue
import grails.test.mixin.TestFor
import spock.lang.Specification
@TestFor(MyService)
class MyServiceSpec extends Specification {
def setup() {
grailsApplication.config.myProperty = 'myValue'
}
void "It fails to initialize the service"() {
expect:
false // this is never executed
}
}
这里的第二个测试:
package issue
import grails.test.mixin.TestFor
import spock.lang.Specification
@TestFor(MyService)
class MyServiceWithSharedInstanceInitializationSpec extends Specification {
//Initializing the shared instance grailsApplication lets the @PostConstruct work, but will fail during method test
//because the instance that was initialized is the shared instance
def setupSpec() {
grailsApplication.config.myProperty = 'myValue'
}
void "It fails to execute doSomething"() {
when:
service.doSomething()
then:
def e = thrown(NullPointerException)
e.message == 'Cannot invoke method toLowerCase() on null object'
service.property == null
}
}
有没有干净地做到这一点?还是我不得不放手我的单元测试,只是做一个(较慢)的集成测试,tip this这个奇怪?
你可以看到我的全部的Grails应用程序的位置:
https://github.com/LuisMuniz/grails-spock-issue-with-postconstruct
答
我的初始化代码要么失败,因为我不添加setupSpec初始化共享实例,或者在方法下测试失败,因为该配置实际上并未在该实例上设置。
我的建议是简单地调用init方法,因为你正在测试的方法的逻辑和功能,不在于是否@PostConstruct
作品,这似乎使最有意义。
没错,那是可以接受的。测试@PostConstuct是一个集成方面 – loteq