Spock:可以在测试用例中替换setup()中定义的交互吗?

时间:2014-03-06 05:38:11

标签: unit-testing groovy spock

我很难在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:说再见: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")
}

但是两个都失败了同样的你好并不等于再见消息。

我可能仍然在Mockito模式中思考,并假设交互相当于when(...).thenReturn(...)表达式,后来的交互会覆盖早期的交互。

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

1 个答案:

答案 0 :(得分:23)

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

def setup() {
    bar.message >> "hello"
}

def "say goodbye"() {
    when:
    def msg = foo.message

    then:
    bar.message >> "goodbye"
    msg == "goodbye"
}

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