新建实例的Spock验证方法调用

问题描述 投票:0回答:1

我正在尝试验证是否为新创建的实例调用了某些方法。

我遵循了模拟构造函数的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();仍返回新实例而不是模拟的步骤。

unit-testing groovy mocking spock
1个回答
0
投票

不要使用诸如全局Groovy模拟之类的肮脏技巧,而是要进行重构以实现解耦,依赖注入以及由此带来的更好的可测试性。请阅读我的答案here的“一般评论”和“更多说明”部分,以了解您应该重构的原因。我不想在这里重复所有内容。

由于技术原因,您的全局Groovy模拟无法在Java代码中运行,因此我引用了Spock manaual

什么时候应该比常规的模拟更喜欢Groovy的模拟?

当规范下的代码为用Groovy编写,一些独特的Groovy模拟功能是需要。 当从Java代码中调用时,Groovy模拟的行为类似于常规模拟。请注意,没有必要使用Groovy模拟仅因为规范和/或模拟类型下的代码是用Groovy编写。除非您有具体的理由使用Groovy模拟,更喜欢常规模拟。


更新:

最快的重构方法是将创建步骤与添加目标分开。实际上,名称createStep表示该方法就是这样做的。但是相反,它还会添加目标。为此使用两种方法,另一种是执行工作流的方法。然后,您可以使用Spy存根createStep(它返回创建的Step实例),然后检查交互,如果您真的认为应该进行测试。检查内部交互通常是一种代码味道(规格过高)。

或者,为步骤添加工厂类,并将实例注入工作流类。然后,您可以轻松模拟工厂类,并使其返回模拟步骤。

如果您不理解这两种选择的意思,请告诉我。

© www.soinside.com 2019 - 2024. All rights reserved.