The*_*ent 4 java groovy unit-testing spock
我使用以下测试作为示例来展示我遇到的类似问题。我认为这只是我对 SpockFramework 中全局模拟如何工作的误解。
void "test"() {
when:
TestStage stage = new TestStage("John")
GroovyMock(TestStep.class, global: true) {
getName() >> "Joe"
}
then:
stage.run() == "Joe"
}
Run Code Online (Sandbox Code Playgroud)
此测试应创建一个提供默认名称的测试阶段。但随后我在其中创建一个类的全局模拟TestStage以覆盖返回值。TestStageIE:我只是想测试not的功能TestStep。如果TestStep只进行更改,我不想知道它们,我将单独测试它们。但是,当我运行此测试时,全局模拟似乎永远不会生效"John",因为返回的名称仍然是我最初提供的名称。
stage.run() == "Joe"
| | |
| John false
Run Code Online (Sandbox Code Playgroud)
这是用于测试这一点的两个示例类。
class TestStage {
TestStep step
TestStage(String name) {
this.step = new TestStep(name)
}
String run() {
return step.getName()
}
}
Run Code Online (Sandbox Code Playgroud)
class TestStep {
private String name
TestStep(String name) {
this.name = name
}
String getName() {
return this.name
}
}
Run Code Online (Sandbox Code Playgroud)
事实上,你在这里问了一个很好的问题。根据 Spock 手册,似乎您可以使用GroovyMockandGroovyStub来全局替换实例并存根它们的方法,就像您尝试做的那样,即使如果我是您,我也会先创建全局模拟对象,然后再隐式使用它对象的构造函数取决于它。但无论如何,它并没有像你说的那样按预期工作。
当我在 Spock 手册和 Spock 源代码中搜索有关 的示例时GroovyMock,除了静态方法之外,我没有找到任何涉及其他内容的示例。实际上,那里的测试覆盖率相当糟糕。通常,如果手册对我没有帮助,我会看看是否可以从测试中推断出如何使用某个功能。在这种情况下,我只能自己尝试一下。
我注意到的第一件事是完全违反直觉的事实,当在全局GroovyMockor上调用构造函数时GroovyStub,它返回null!这是一个真正的警告。在某种程度上,构造函数在这里被视为普通的模拟方法,也返回null. 没有任何官方消息来源提到这一点,而且我还认为应该将其更改为默认返回正常的 Spock 模拟(如果该类是可模拟的,即非最终的)。
现在这也是解决方案的关键:您需要存根一个或多个构造函数以返回除 之外的其他内容null,例如先前创建的普通实例或 Spock 模拟/存根/间谍。
这是源代码的稍微修改的版本。我重命名了应用程序类,以便Test它们的名称中不包含这些内容。所有这些Test类名对我来说都有点令人困惑,特别是因为我也将我的 Spock 规范命名为*Test,就像我通常做的那样,而不是*Spec,因为这样 Maven Surefire/Failsafe 就可以自动检测到它,而无需额外的配置。
我还向要模拟的类添加了一个静态方法,以便向您展示对其进行存根的语法。这只是一个免费的附加组件,与您的问题没有直接关系。
我的测试显示了三种变体:
GroovySpy,它始终基于真实对象(或指示创建一个对象)。因此,您不需要存根构造函数。GroovyMock。在我的示例中,它返回一个带有存根方法的常规 Spock 模拟,但它也可以返回一个普通实例。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"
}
}
Run Code Online (Sandbox Code Playgroud)
package de.scrum_master.stackoverflow.q61667088
class Stage {
Step step
Stage(String name) {
this.step = new Step(name)
}
String run() {
return step.getName()
}
}
Run Code Online (Sandbox Code Playgroud)
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"
}
}
Run Code Online (Sandbox Code Playgroud)
PS:我认为,您可能阅读了 Spock 手册,但以防万一:如果您的GroovyMock/Stub/Spy目标是用 Groovy 以外的语言(例如 Java 或 Kotlin)实现的,那么这将不起作用,因为那样Groovy*会表现得像常规的 Spock 模拟/存根/间谍。
更新:我刚刚创建了Spock 问题 #1159,首先是为了记录这种行为并通过测试覆盖,但为了让它也发生变化,如果它不是这样的。
| 归档时间: |
|
| 查看次数: |
2660 次 |
| 最近记录: |