1

似乎在测试用例中使用 rspec 模拟的标准方法是执行以下操作:

class MyTest
  def setup
    super
    ::RSpec::Mocks.setup(self)
  end

  def teardown
    super
    begin
      ::RSpec::Mocks.verify
    ensure
      ::RSpec::Mocks.teardown
    end
  end

  test "something"
    foo = MyFoo.new
    expect(foo).to receive(:bar).and_return(42)
    ret = SomeClass.call_bar(foo)

    assert_equal(42, ret)
  end
end

行得通。但是,如果SomeClass.call_bar使用 return offoo.bar作为返回,并且代码有问题,以至于foo.bar从未调用过,那么我只会收到由于该assert_equal(42, ret)行导致的失败。我没有看到任何错误,例如:

RSpec::Mocks::MockExpectationError: (foo).bar
    expected: 1 time
    received: 0 times

如果我删除该assert_equal(42, ret)行,那么我会得到 rspec 期望错误。但是我想验证这两件事,foo.bar即被调用最终返回为 42。更重要的是要知道foo.bar没有调用,因为这是没有返回 42 的原因。

如果我期待类似:expect(foo).not_to receive(:bar),那么我确实在调用的源头得到了那个期望错误,而不是在拆解的后期。

现在,我可以::RSpec::Mocks.verify在调用 to 之前执行 put 之类的操作assert_equal,但这感觉不对。我也不确定我是否应该在这一点上清理模拟。

是否有一些语法,例如:

  test "something"
    foo = MyFoo.new
    ret = nil

    expect(foo).to receive(:bar).and_return(42).during do
      ret = SomeClass.call_bar(foo)
    end

    assert_equal(42, ret)
  end

这样验证会在块传递给during? 或者,如果您有多个双打,您可以执行以下操作:

    expect(dbl1).to receive(:one)
    expect(dbl2).to receive(:two)
    expect(dbl3).to receive(:three)

    verify(dbl1, dbl2, dbl3).during do
      my_code
    end
4

3 回答 3

3

您正在寻找rspec 间谍

Spies 是另一种类型的测试替身,它通过允许您期望在事后收到消息来支持此模式,使用have_received.

您从foowith中创建部分双allow(...).to receive精度,然后可以断言接收到消息:

test "something"
  foo = MyFoo.new
  allow(foo).to receive(:bar).and_return(42)
  ret = SomeClass.call_bar(foo)
  expect(foo).to have_received(:bar)
  assert_equal(42, ret)
end
于 2019-06-27T16:48:18.637 回答
1

我相信你需要的是聚合失败 https://relishapp.com/rspec/rspec-expectations/v/3-8/docs/aggregating-failures

在“正常”设置中,任何错误都会中止测试,并且不会检查以后的断言。

于 2019-06-27T16:57:36.110 回答
-2

我认为没有任何内置方法可以做到这一点,但是如果您添加以下类:

class VerifyDuring
  def initialize(test, objects)
    @test = test
    @objects = objects
  end

  def during
    yield
  ensure
    begin
      @objects.each do |object|
        RSpec::Mocks.proxy_for(object).verify
      end
    rescue Exception => e
      @test.flunk e
    end
  end
end

以及您的测试类的以下方法:

  def verify(*objects)
    VerifyDuring.new(self, objects)
  end

你可以这样做:

    verify(dbl1, dbl2, dbl3).during do
      my_code
    end
于 2019-06-27T16:01:13.073 回答