块实现

当您传递一个块时,RSpec 将使用您的块作为该方法的实现。调用者提供的任何参数(或块)都将传递给您的块实现。此功能极其灵活,支持许多更具声明性的流畅接口不支持的用例。

您可以将块传递给任何流畅接口方法

* `allow(dbl).to receive(:foo) { do_something }`
* `allow(dbl).to receive(:foo).with("args") { do_something }`
* `allow(dbl).to receive(:foo).once { do_something }`
* `allow(dbl).to receive(:foo).ordered { do_something }`

下面显示了一些块实现的更常见用例,但这并不详尽。

使用块以更简洁的语法指定返回值

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

RSpec.describe "Specifying a return value using a block" do
  it "returns the block's return value" do
    dbl = double
    allow(dbl).to receive(:foo) { 14 }
    expect(dbl.foo).to eq(14)
  end
end

我运行 `rspec return_value_spec.rb` 时

那么这些示例应该全部通过。

使用块验证参数

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

RSpec.describe "Verifying arguments using a block" do
  it "fails when the arguments do not meet the expectations set in the block" do
    dbl = double

    allow(dbl).to receive(:foo) do |arg|
      expect(arg).to eq("bar")
    end

    dbl.foo(nil)
  end
end

我运行 `rspec verify_arguments_spec.rb` 时

那么它应该失败,并提示

Failure/Error: expect(arg).to eq("bar")

使用块执行计算

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

RSpec.describe "Performing a calculation using a block" do
  it "returns the block's return value" do
    loan = double("Loan", :amount => 100)

    allow(loan).to receive(:required_payment_for_rate) do |rate|
      loan.amount * rate
    end

    expect(loan.required_payment_for_rate(0.05)).to eq(5)
    expect(loan.required_payment_for_rate(0.1)).to eq(10)
  end
end

我运行 `rspec perform_calculation_spec.rb` 时

那么这些示例应该全部通过。

生成给调用者的块

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

RSpec.describe "When the caller passes a block" do
  it "can be yielded to from your implementation block" do
    dbl = double
    allow(dbl).to receive(:foo) { |&block| block.call(14) }
    expect { |probe| dbl.foo(&probe) }.to yield_with_args(14)
  end
end

我运行 `rspec yield_to_caller_spec.rb` 时

那么这些示例应该全部通过。

在块中委托给部分替身的原始实现

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

class Calculator
  def self.add(x, y)
    x + y
  end
end

RSpec.describe "When using a block implementation on a partial double" do
  it "supports delegating to the original implementation" do
    original_add = Calculator.method(:add)

    allow(Calculator).to receive(:add) do |x, y|
      original_add.call(x, y) * 2
    end

    expect(Calculator.add(2, 5)).to eq(14)
  end
end

我运行 `rspec delegate_to_original_spec.rb` 时

那么这些示例应该全部通过。

模拟瞬态网络故障

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

RSpec.describe "An HTTP API client" do
  it "can simulate transient network failures" do
    client = double("MyHTTPClient")

    call_count = 0
    allow(client).to receive(:fetch_data) do
      call_count += 1
      call_count.odd? ? raise("timeout") : { :count => 15 }
    end

    expect { client.fetch_data }.to raise_error("timeout")
    expect(client.fetch_data).to eq(:count => 15)
    expect { client.fetch_data }.to raise_error("timeout")
    expect(client.fetch_data).to eq(:count => 15)
  end
end

我运行 `rspec simulate_transient_network_failure_spec.rb` 时

那么这些示例应该全部通过。