间谍

消息期望 将示例的期望放在开头,在你调用被测代码之前。许多开发人员更喜欢使用安排-行动-断言(或给定-何时-然后)模式来构建测试。间谍是一种支持这种模式的备选测试替身类型,它允许你使用 `have_received` 在事后期望收到一条消息。

你可以使用任何测试替身(或部分替身)作为间谍,但替身必须设置为监视你关心的消息。间谍会自动监视所有消息,或者你可以 允许一条消息 来监视它。

have_received 支持与普通消息期望相同的流畅接口,用于 设置约束

注意:这里显示的 `have_received` API 仅适用于使用 rspec-expectations 的情况。注意:当传递的参数在间谍记录接收的消息后被更改时,`have_received(...).with(...)` 无法正常工作。

使用间谍

给定 一个名为“spy_spec.rb”的文件,其中包含

RSpec.describe "have_received" do
  it "passes when the message has been received" do
    invitation = spy('invitation')
    invitation.deliver
    expect(invitation).to have_received(:deliver)
  end
end

我运行 `rspec spy_spec.rb` 时

那么 这些示例都应该通过。

监视部分替身上的方法

给定 一个名为“partial_double_spy_spec.rb”的文件,其中包含

class Invitation
  def self.deliver; end
end

RSpec.describe "have_received" do
  it "passes when the expectation is met" do
    allow(Invitation).to receive(:deliver)
    Invitation.deliver
    expect(Invitation).to have_received(:deliver)
  end
end

我运行 `rspec partial_double_spy_spec.rb` 时

那么 这些示例都应该通过。

消息未收到时的失败

给定 一个名为“failure_spec.rb”的文件,其中包含

class Invitation
  def self.deliver; end
end

RSpec.describe "failure when the message has not been received" do
  example "for a spy" do
    invitation = spy('invitation')
    expect(invitation).to have_received(:deliver)
  end

  example "for a partial double" do
    allow(Invitation).to receive(:deliver)
    expect(Invitation).to have_received(:deliver)
  end
end

我运行 `rspec failure_spec.rb --order defined` 时

那么 它应该失败,并显示以下信息

  1) failure when the message has not been received for a spy
     Failure/Error: expect(invitation).to have_received(:deliver)

       (Double "invitation").deliver(*(any args))
           expected: 1 time with any arguments
           received: 0 times with any arguments

并且 它应该失败,并显示以下信息

  2) failure when the message has not been received for a partial double
     Failure/Error: expect(Invitation).to have_received(:deliver)

       (Invitation (class)).deliver(*(any args))
           expected: 1 time with any arguments
           received: 0 times with any arguments

使用流畅接口设置约束

给定 一个名为“setting_constraints_spec.rb”的文件,其中包含

RSpec.describe "An invitation" do
  let(:invitation) { spy("invitation") }

  before do
    invitation.deliver("foo@example.com")
    invitation.deliver("bar@example.com")
  end

  it "passes when a count constraint is satisfied" do
    expect(invitation).to have_received(:deliver).twice
  end

  it "passes when an order constraint is satisfied" do
    expect(invitation).to have_received(:deliver).with("foo@example.com").ordered
    expect(invitation).to have_received(:deliver).with("bar@example.com").ordered
  end

  it "fails when a count constraint is not satisfied" do
    expect(invitation).to have_received(:deliver).at_least(3).times
  end

  it "fails when an order constraint is not satisfied" do
    expect(invitation).to have_received(:deliver).with("bar@example.com").ordered
    expect(invitation).to have_received(:deliver).with("foo@example.com").ordered
  end
end

我运行 `rspec setting_constraints_spec.rb --order defined` 时

那么 它应该失败,并显示以下输出

4 个示例,2 个失败
1) 当计数约束不满足时,邀请失败
Failure/Error: expect(invitation).to have_received(:deliver).at_least(3).times
(Double “invitation”).deliver(*(any args))
预期:至少 3 次,任何参数
收到:2 次,任何参数
2) 当顺序约束不满足时,邀请失败
Failure/Error: expect(invitation).to have_received(:deliver).with(“foo@example.com”).ordered
#接收 :deliver 的顺序错误