【问题标题】:Spock: can an interaction defined in setup() be replaced in a test case?Spock:可以在测试用例中替换 setup() 中定义的交互吗?
【发布时间】:2014-04-08 14:00:46
【问题描述】:

我很难理解 Groovy 单元测试中的 Spock 交互。

我有以下几种:

public interface Bar {
  public String getMessage();
}

public class Foo {
  private Bar bar;
  public void setBar(Bar bar) {
    this.bar = bar;
  }
  public String getMessage() {
    return bar.getMessage();
  }
}

然后我编写了以下 Groovy/Spock 测试:

class FooSpec extends Specification {

  private Bar bar;
  private Foo foo;

  def setup() {
    bar = Mock(Bar) { getMessage() >> "hello" }
    foo = new Foo()
    foo.bar = bar
  }

  def "say hello"() {
    expect:
    foo.message.equals("hello")
  }

  def "say goodbye"() {
    setup:
    bar.getMessage() >> "goodbye"

    expect:
    foo.message.equals("goodbye")
  }
}

代码在设置中创建了一个模拟Bar 实例,初始化Bar.getMessage() 以返回hello,并将其分配给一个新的Foo 实例。

第一个测试验证foo.getMessage() 等于hello

第二个测试尝试修改bar 模拟,使其getMessage 方法返回goodbye。然后我们期望foo.getMessage()(代表bar.getMessage())将返回goodbye。但是测试失败如下:

FooSpec:say goodbye:26 条件不满足

因为foo.message 仍然等于hello

我还尝试了以下方法:

def "say goodbye"() {
  when:
  bar.getMessage() >> "goodbye"

  then:
  foo.message.equals("goodbye")
}

和:

def "say goodbye"() {
  when:
  no_op()

  then:
  bar.getMessage() >> "goodbye"
  foo.message.equals("goodbye")
}

但两者都以相同的 hello does not equal goodbye 消息失败。

我可能仍在考虑 Mockito 模式,并假设交互相当于 when(...).thenReturn(...) 表达式,并且以后的交互将覆盖早期的交互。

有没有一种简单的方法使用 Spock 在 setup 方法中声明交互,然后在测试用例中覆盖该交互?还是我需要删除setup() 方法并基本上为每个测试用例添加一个setup: 块?

【问题讨论】:

    标签: unit-testing groovy spock


    【解决方案1】:

    这是一个棘手的问题。如docs 中所述,在 then 块中声明的交互优先于之前声明的交互。但是,在 then 块中声明的交互作用域是前一个 when 块。 (这允许有多个 when-then 对。)因此您的最后一次尝试不起作用,但以下将:

    def setup() {
        bar.message >> "hello"
    }
    
    def "say goodbye"() {
        when:
        def msg = foo.message
    
        then:
        bar.message >> "goodbye"
        msg == "goodbye"
    }
    

    我同意在测试方法中声明的交互总是覆盖在设置方法中声明的交互会很好。无论如何,覆盖交互的一个很好的替代方法是让每个测试方法调用一个辅助方法,该方法为该测试方法设置预期的交互。

    【讨论】:

    • 感谢您的评论。我将避免使用setup() 方法并更改我的测试方法以直接初始化它们的状态(这也是因为我经常在我的测试方法中使用where: 块,我惊讶地发现setup() 方法是在 where: 块之后调用的)。我认为我可以理解您上面的示例,但它并不直观(在我看来,它仍然像 then: 块中的设置代码)。
    • @PeterNiederwieser,你在这个例子中使用了哪个 Spock 版本?我们已经在 Spock 1.0 中尝试过这个以及许多其他变体,但都没有奏效。
    • @JohnQCitizen 当我想要断言服务方法已被调用一定次数以及控制返回的数据时,我经常使用这种策略。我想在这个例子中,我会把它放在given: 块中。
    猜你喜欢
    • 2021-08-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-12-26
    • 1970-01-01
    • 2014-11-05
    • 1970-01-01
    相关资源
    最近更新 更多