У меня есть служба, которую я хочу инициализировать с помощью @PostConstuct
, извлекая некоторые записи конфигурации в Config.groovy
.Обслуживание нестационарных графов (2.5.4) с использованием @PostConstruct с тестированием модуля Spock
Я также хочу проверить правильность настройки этих записей и выбросить исключение, чтобы я увидел, что приложение было неправильно сконфигурировано.
При написании модульного теста для этой услуги я пришел в тупик в Споке.
Спок, по-видимому, вызывает метод @PostConstruct
, но только на экземпляре Shared Service, а затем выполняет любые методы экземпляра, которые вы тестируете, в реальном тестируемом экземпляре.
Это извращенный побочный эффект:
Моей инициализация код либо не удается, потому что я не добавить 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
}
}
Есть ли способ сделать это чисто? Или мне нужно отпустить мой модульный тест и просто сделать (медленнее) интеграционный тест, на цыпочках вокруг этой странности?
Вы можете увидеть мое полное Grails приложение здесь:
https://github.com/LuisMuniz/grails-spock-issue-with-postconstruct
Правда, это приемлемо. Тестирование @PostConstuct является аспектом интеграции – loteq