2016-07-30 102 views
3

我有一項服務,我希望通過@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

回答

2

我的初始化代碼要麼失敗,因爲我不添加setupSpec初始化共享實例,或者在方法下測試失敗,因爲該配置實際上並未在該實例上設置。

我的建議是簡單地調用init方法,因爲你正在測試的方法的邏輯和功能,不在於是否@PostConstruct作品,這似乎使最有意義。

+0

沒錯,那是可以接受的。測試@PostConstuct是一個集成方面 – loteq