На самом деле, вы задаете здесь хороший вопрос, потому что, согласно руководству Spock, кажется, что вы могли бы использовать GroovyMock
и GroovyStub
для глобальной замены экземпляров и заглушки их методов, как вы пытались сделать, даже если на вашем месте я бы сначала создал глобальный фиктивный объект, прежде чем неявно использовать его в конструкторе объекта в зависимости от него. Но в любом случае, как вы и сказали, это не работает так, как ожидалось.
Когда я искал в руководстве Spock и исходном коде Spock примеры, касающиеся GroovyMock
, нигде я не нашел ни одного, включающего что-либо иное, кроме stati c методов. На самом деле, покрытие там довольно плохое. Обычно, если руководство мне не помогает, я смотрю, смогу ли я сделать вывод из тестов, как использовать функцию. В этом случае мне пришлось попробовать самому.
Первое, что я заметил, это совершенно противоречивый факт, что при вызове конструктора в глобальном GroovyMock
или GroovyStub
возвращает null
!!! Это настоящий нюанс. В некотором смысле конструкторы здесь обрабатываются как обычные фиктивные методы, также возвращающие null
. Нигде в официальных источниках это не упоминается, и я также думаю, что его следует изменить на значение по умолчанию, чтобы вместо этого возвращался обычный макет Spock (если класс является макетом, то есть не окончательным).
Теперь это также ключ к Решение : вам нужно заглушить один или несколько конструкторов, чтобы вернуть что-то еще, кроме null
, , например, ранее созданный нормальный экземпляр или mock / stub / spy Spock.
Вот слегка измененная версия вашего исходного кода (я переименовал классы приложений, чтобы не содержать «Test» в их именах, потому что все эти «Test» меня немного сбивали с толку, особенно потому, что я также назвал свой тестовый класс «* Test» , как я обычно это делаю вместо «* Spe c», потому что тогда Maven Surefire / Failsafe подберет его автоматически без дополнительной настройки.
Я также добавил метод stati c к классу, который будет издеваться чтобы показать вам синтаксис заглушки. это просто бесплатное дополнение, не имеющее прямого отношения к вашему вопросу.
Мой тест показывает три варианта:
- с использованием классического имита Спока и инъекцией его испытуемому
- с использованием глобального
GroovySpy
, который всегда основан на реальном объекте (или получил указание создать one), и, следовательно, вам не нужно заглушать конструктор - , используя глобальный
GroovyMock
с явно заглушенным конструктором, в моем примере, возвращающий обычный макет Spock с заглушенным методом, но он также может возвращать нормальный instance.
package de.scrum_master.stackoverflow.q61667088
class Step {
private String name
Step(String name) {
this.name = name
}
String getName() {
return this.name
}
static String staticMethod() {
return "original"
}
}
package de.scrum_master.stackoverflow.q61667088
class Stage {
Step step
Stage(String name) {
this.step = new Step(name)
}
String run() {
return step.getName()
}
}
package de.scrum_master.stackoverflow.q61667088
import spock.lang.Specification
class GlobalMockTest extends Specification {
def "use Spock mock"() {
given:
def step = Mock(Step) {
getName() >> "Joe"
}
def stage = new Stage("John")
stage.step = step
expect:
stage.run() == "Joe"
}
def "use global GroovySpy"() {
given:
GroovySpy(Step, global: true) {
getName() >> "Joe"
}
Step.staticMethod() >> "stubbed"
def stage = new Stage("John")
expect:
Step.staticMethod() == "stubbed"
stage.run() == "Joe"
}
def "use global GroovyMock"() {
given:
GroovyMock(Step, global: true)
new Step(*_) >> Mock(Step) {
getName() >> "Joe"
}
Step.staticMethod() >> "stubbed"
def stage = new Stage("John")
expect:
Step.staticMethod() == "stubbed"
stage.run() == "Joe"
}
}
PS: Я думаю, вы, вероятно, читали руководство Spock, но на всякий случай: если ваша цель GroovyMock/Stub/Spy
реализована на языке, отличном от Groovy например, Java или Kotlin, это не сработает, потому что тогда Groovy*
будет вести себя как обычный mock / stub / spy Spock.
Обновление: Я только что создал проблему Спока # 1159 для того, чтобы это поведение было задокументировано и покрыто тестами, а также изменилось, если оно не предназначалось для этого.