我有一項服務,我希望通過@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
沒錯,那是可以接受的。測試@PostConstuct是一個集成方面 – loteq