首页 文章

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

提问于
浏览
23

我很难在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 回答

  • 22

    这是一个棘手的问题 . 如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方法中声明的交互 . 无论如何,覆盖交互的一个很好的替代方法是每个测试方法调用一个辅助方法来设置该测试方法的预期交互 .

相关问题