1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131
|
Feature: Block implementation
When you pass a block, RSpec will use your block as the implementation of the method. Any
arguments (or a block) provided by the caller will be yielded to your block implementation.
This feature is extremely flexible, and supports many use cases that are not directly
supported by the more declaritive fluent interface.
You can pass a block to any of the fluent interface methods:
* `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 }`
Some of the more common use cases for block implementations are shown below, but this
is not an exhaustive list.
Scenario: Use a block to specify a return value with a terser syntax
Given a file named "return_value_spec.rb" with:
"""ruby
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
"""
When I run `rspec return_value_spec.rb`
Then the examples should all pass
Scenario: Use a block to verify arguments
Given a file named "verify_arguments_spec.rb" with:
"""ruby
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
"""
When I run `rspec verify_arguments_spec.rb`
Then it should fail with:
"""
Failure/Error: expect(arg).to eq("bar")
"""
Scenario: Use a block to perform a calculation
Given a file named "perform_calculation_spec.rb" with:
"""ruby
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
"""
When I run `rspec perform_calculation_spec.rb`
Then the examples should all pass
Scenario: Yield to the caller's block
Given a file named "yield_to_caller_spec.rb" with:
"""ruby
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
"""
When I run `rspec yield_to_caller_spec.rb`
Then the examples should all pass
Scenario: Delegate to partial double's original implementation within the block
Given a file named "delegate_to_original_spec.rb" with:
"""ruby
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
"""
When I run `rspec delegate_to_original_spec.rb`
Then the examples should all pass
Scenario: Simulating a transient network failure
Given a file named "simulate_transient_network_failure_spec.rb" with:
"""ruby
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
"""
When I run `rspec simulate_transient_network_failure_spec.rb`
Then the examples should all pass
|