我正在尝试验证是否为新创建的实例调用了某些方法。
我遵循了模拟构造函数的Spock指南,但是它说的调用太少了。
Too few invocations for:
3 * mockStep.addTarget(_) (0 invocations)
Unmatched invocations (ordered by similarity):
None
在此处粘贴我的代码...
public class Workflow {
public void createStep() {
Step step = new Step();
step.addTarget("A");
step.addTarget("B");
step.addTarget("C");
}
}
class WorkflowTest extends Specification {
Workflow workflow
def setup() {
workflow = new Workflow()
}
def "each new step should have 3 targets" () {
given:
def mockStep = Mock(Step)
GroovySpy(Step, global: true)
new Step() >> mockStep
when:
workflow.createStep()
then:
3 * mockStep.addTarget(_)
}
}
在上面的代码中,我试图让所有新的Step()返回模拟的Step,并验证模拟步骤(3)。当我在调试模式下运行时,似乎Step step = new Step();
仍返回新实例而不是模拟的步骤。
不要使用诸如全局Groovy模拟之类的肮脏技巧,而是要进行重构以实现解耦,依赖注入以及由此带来的更好的可测试性。请阅读我的答案here的“一般评论”和“更多说明”部分,以了解您应该重构的原因。我不想在这里重复所有内容。
由于技术原因,您的全局Groovy模拟无法在Java代码中运行,因此我引用了Spock manaual:
什么时候应该比常规的模拟更喜欢Groovy的模拟?
当规范下的代码为用Groovy编写,一些独特的Groovy模拟功能是需要。 当从Java代码中调用时,Groovy模拟的行为类似于常规模拟。请注意,没有必要使用Groovy模拟仅因为规范和/或模拟类型下的代码是用Groovy编写。除非您有具体的理由使用Groovy模拟,更喜欢常规模拟。
更新:
最快的重构方法是将创建步骤与添加目标分开。实际上,名称createStep
表示该方法就是这样做的。但是相反,它还会添加目标。为此使用两种方法,另一种是执行工作流的方法。然后,您可以使用Spy
存根createStep
(它返回创建的Step
实例),然后检查交互,如果您真的认为应该进行测试。检查内部交互通常是一种代码味道(规格过高)。
或者,为步骤添加工厂类,并将实例注入工作流类。然后,您可以轻松模拟工厂类,并使其返回模拟步骤。
如果您不理解这两种选择的意思,请告诉我。