diff --git a/features/message_expectations/allow_any_instance_of.feature b/features/message_expectations/allow_any_instance_of.feature new file mode 100644 index 000000000..5bf42dda6 --- /dev/null +++ b/features/message_expectations/allow_any_instance_of.feature @@ -0,0 +1,26 @@ +Feature: allow a message on any instance of a class + + Use `allow_any_instance_of(Class).to receive` when you want to configure how + instances of the given class respond to a message without setting an + expectation that the message will be received. + + Scenario: allowing a message on any instance of a class + Given a file named "example_spec.rb" with: + """ruby + describe "any_instance.should_receive" do + before do + allow_any_instance_of(Object).to receive(:foo).and_return(:return_value) + end + + it "allows any instance of the class to receive the message" do + o = Object.new + expect(o.foo).to eq(:return_value) + end + + it "passes even if no instances receive that message" do + o = Object.new + end + end + """ + When I run `rspec example_spec.rb` + Then the examples should all pass diff --git a/features/message_expectations/expect_any_instance_of.feature b/features/message_expectations/expect_any_instance_of.feature index 1b2802e02..b0b061814 100644 --- a/features/message_expectations/expect_any_instance_of.feature +++ b/features/message_expectations/expect_any_instance_of.feature @@ -1,13 +1,9 @@ -Feature: expect/allow a message on any instance of a class +Feature: expect a message on any instance of a class Use `expect_any_instance_of(Class).to receive` to set an expectation that one (and only one) instance of a class receives a message before the example is completed. The spec will fail if no instance receives a message. - Use `allow_any_instance_of(Class).to receive` when an instance of a class may - respond to a particular message. This will not set an expectation on any instance - so the spec will not fail if no instance receives the message. - Scenario: expect a message on any instance of a class Given a file named "example_spec.rb" with: """ruby @@ -21,32 +17,11 @@ Feature: expect/allow a message on any instance of a class expect(o.foo).to eq(:return_value) end - it "fails if no instance receives that message" do + it "fails unless an instance receives that message" do o = Object.new end end """ When I run `rspec example_spec.rb` Then the output should contain "2 examples, 1 failure" - And the output should contain "1) expect_any_instance_of fails if no instance receives that message" - - Scenario: allowing a message on any instance of a class - Given a file named "example_spec.rb" with: - """ruby - describe "any_instance.should_receive" do - before do - allow_any_instance_of(Object).to receive(:foo).and_return(:return_value) - end - - it "allows any instance of the class to receive the message" do - o = Object.new - expect(o.foo).to eq(:return_value) - end - - it "wont fail if no instances receive that message" do - o = Object.new - end - end - """ - When I run `rspec example_spec.rb` - Then the examples should all pass + And the output should contain "1) expect_any_instance_of fails unless an instance receives that message" diff --git a/features/method_stubs/README.md b/features/method_stubs/README.md index 014b2fc5e..81e6e883a 100644 --- a/features/method_stubs/README.md +++ b/features/method_stubs/README.md @@ -3,7 +3,11 @@ # create a double obj = double() - # specify a return value + # specify a return value using `:expect` syntax + allow(obj).to receive(:message) { :value } + allow(obj).to receive(:message).and_return(:value) + + # specify a return value using `:should` syntax obj.stub(:message) { :value } obj.stub(:message => :value) obj.stub(:message).and_return(:value) @@ -14,18 +18,29 @@ block contents are evaluated lazily when the `obj` receives the ### Fake implementation + allow(obj).to receive(:message) do |arg1, arg2| + # set expectations about the args in this block + # and/or return value + end + obj.stub(:message) do |arg1, arg2| # set expectations about the args in this block - # and/or set a return value + # and/or return a value end ### Raising/Throwing + allow(obj).to receive(:message).and_raise("this error") + allow(obj).to receive(:message).and_throw(:this_symbol) + obj.stub(:message).and_raise("this error") obj.stub(:message).and_throw(:this_symbol) You can also use the block format: + allow(obj).to receive(:message) { raise "this error" } + allow(obj).to receive(:message) { throw :this_symbol } + obj.stub(:message) { raise "this error" } obj.stub(:message) { throw :this_symbol } @@ -33,11 +48,20 @@ You can also use the block format: #### Explicit arguments + allow(obj).to receive(:message).with('an argument') { ... } + obj.stub(:message).with('an argument') { ... } obj.stub(:message).with('more_than', 'one_argument') { ... } #### Argument matchers + allow(obj).to receive(:message).with(anything()) { ... } + allow(obj).to receive(:message).with(an_instance_of(Money)) { ... } + allow(obj).to receive(:message).with(hash_including(:a => 'b')) { ... } + allow(obj).to receive(:message).with(array_including(1,2,3)) { ... } + # or + allow(obj).to receive(:message).with(array_including([1,2,3])) { ... } + obj.stub(:message).with(anything()) { ... } obj.stub(:message).with(an_instance_of(Money)) { ... } obj.stub(:message).with(hash_including(:a => 'b')) { ... } @@ -47,4 +71,6 @@ You can also use the block format: #### Regular expressions + allow(obj).to receive(:message).with(/abc/) { ... } + obj.stub(:message).with(/abc/) { ... } diff --git a/features/method_stubs/any_instance.feature b/features/method_stubs/any_instance.feature index bb7115baa..65e84eede 100644 --- a/features/method_stubs/any_instance.feature +++ b/features/method_stubs/any_instance.feature @@ -6,6 +6,10 @@ Feature: stub on any instance of a class Messages can be stubbed on any class, including those in Ruby's core library. + Note: You can use `allow_any_instance_of` when you don't have a reference + to the object that receives a message in your test. For more information, + see the message_expectations/allow_any_instance_of feature. + Scenario: any_instance stub with a single return value Given a file named "example_spec.rb" with: """ruby @@ -129,4 +133,4 @@ Feature: stub on any instance of a class end """ When I run `rspec stub_chain_spec.rb` - Then the examples should all pass \ No newline at end of file + Then the examples should all pass diff --git a/features/method_stubs/as_null_object.feature b/features/method_stubs/as_null_object.feature index b1ee3618c..afddf9e0c 100644 --- a/features/method_stubs/as_null_object.feature +++ b/features/method_stubs/as_null_object.feature @@ -16,7 +16,12 @@ Feature: as_null_object null_object.should respond_to(:an_undefined_method) end - it "allows explicit stubs" do + it "allows explicit stubs using expect syntax" do + allow(null_object).to receive(:foo) { "bar" } + expect(null_object.foo).to eq("bar") + end + + it "allows explicit stubs using should syntax" do null_object.stub(:foo) { "bar" } null_object.foo.should eq("bar") end diff --git a/features/method_stubs/simple_return_value_with_allow.feature b/features/method_stubs/simple_return_value_with_allow.feature new file mode 100644 index 000000000..82fca7500 --- /dev/null +++ b/features/method_stubs/simple_return_value_with_allow.feature @@ -0,0 +1,44 @@ +Feature: allow with a simple return value + + Use the `allow` method with the `receive` matcher on a test double or a real + object to tell the object to return a value (or values) in response to a given + message. Nothing happens if the message is never received. + + Scenario: stub with no return value + Given a file named "example_spec.rb" with: + """ruby + describe "a stub with no return value specified" do + let(:collaborator) { double("collaborator") } + + it "returns nil" do + allow(collaborator).to receive(:message) + expect(collaborator.message).to be(nil) + end + end + """ + When I run `rspec example_spec.rb` + Then the examples should all pass + + Scenario: stubs with return values + Given a file named "example_spec.rb" with: + """ruby + describe "a stub with a return value" do + context "specified in a block" do + it "returns the specified value" do + collaborator = double("collaborator") + allow(collaborator).to receive(:message) { :value } + expect(collaborator.message).to eq(:value) + end + end + + context "specified with #and_return" do + it "returns the specified value" do + collaborator = double("collaborator") + allow(collaborator).to receive(:message).and_return(:value) + expect(collaborator.message).to eq(:value) + end + end + end + """ + When I run `rspec example_spec.rb` + Then the examples should all pass diff --git a/features/method_stubs/simple_return_value.feature b/features/method_stubs/simple_return_value_with_stub.feature similarity index 100% rename from features/method_stubs/simple_return_value.feature rename to features/method_stubs/simple_return_value_with_stub.feature diff --git a/features/method_stubs/stub_implementation.feature b/features/method_stubs/stub_implementation.feature index 269129bd5..581e43dcb 100644 --- a/features/method_stubs/stub_implementation.feature +++ b/features/method_stubs/stub_implementation.feature @@ -3,7 +3,29 @@ Feature: stub with substitute implementation You can stub an implementation of a method (a.k.a. fake) by passing a block to the `stub` method. - Scenario: stub implementation + Scenario: stub implementation using `expect` syntax + Given a file named "stub_implementation_spec.rb" with: + """ruby + describe "a stubbed implementation" do + it "works" do + object = Object.new + allow(object).to receive(:foo) do |arg| + if arg == :this + "got this" + elsif arg == :that + "got that" + end + end + + expect(object.foo(:this)).to eq("got this") + expect(object.foo(:that)).to eq("got that") + end + end + """ + When I run `rspec stub_implementation_spec.rb` + Then the output should contain "1 example, 0 failures" + + Scenario: stub implementation using `should` syntax Given a file named "stub_implementation_spec.rb" with: """ruby describe "a stubbed implementation" do