Feature: Anonymous test doubles Anonymous test doubles can be useful as a stepping stone towards actual fakes and when migrating from another testing library. In contrast with other testing libraries, Bogus makes its fakes respond to all methods by default. This way you can spy on methods without stubbing them first. It is not advisable to use those for anything else than an intermediate step. Fakes that mimic an actual class have many more benefits. The syntax for defining fakes is: fake(method_1: return_value, method_2: proc{return_value2}) If you pass a proc as a return value to a fake, the proc will be called to obtain the value. This can be used for instance to raise errors in stubbed methods. If you want to actually return a proc from a method, you need to use a slightly longer syntax: factory = fake() stub(factory).make_validator{ proc{ false } } Background: Given a file named "student.rb" with: """ruby class Student attr_reader :library_card def initialize(name) @name = name end def sign_up(library) @library_card = library.register_junior(@name) end end """ Scenario: Stubbing any method with any parameters Then spec file with following content should pass: """ruby require_relative 'student' describe Student do let(:library) { fake } let(:jake) { Student.new("Jake") } it "allows stubbing any method with any parameters" do stub(library).register_junior(any_args) { "the card" } jake.sign_up(library) expect(jake.library_card).to eq("the card") end end """ Scenario: Stubbing methods in initializer Then spec file with following content should pass: """ruby require_relative 'student' describe Student do let(:library) { fake(register_junior: "the card") } let(:jake) { Student.new("Jake") } it "allows stubbing any method with any parameters" do jake.sign_up(library) expect(jake.library_card).to eq("the card") end end """ Scenario: Stubbing methods inline by passing a block Then the following test should pass: """ruby library = fake(register_junior: proc{ raise "library full!" }) expect { library.register_junior("Jake") }.to raise_error("library full!") """ Scenario: Mocking any method with any parameters Then spec file with following content should pass: """ruby require_relative 'student' describe Student do let(:library) { fake } let(:jake) { Student.new("Jake") } it "allows mocking any method with any parameters" do mock(library).register_junior("Jake") { "the card" } jake.sign_up(library) expect(jake.library_card).to eq("the card") end end """ Scenario: Mocking any method with any parameters Then spec file with following content should fail: """ruby require_relative 'student' describe Student do it "allows stubbing any method with any parameters" do library = fake mock(library).register_junior { "the card" } end end """ Scenario: Stubbing methods in initializer Then spec file with following content should pass: """ruby require_relative 'student' describe Student do let(:library) { fake(register_junior: "the card") } let(:jake) { Student.new("Jake") } it "allows stubbing any method with any parameters" do jake.sign_up(library) expect(jake.library_card).to eq("the card") end end """ Scenario: Spying on method calls Then spec file with following content should pass: """ruby require_relative 'student' describe Student do let(:library) { fake } let(:jake) { Student.new("Jake") } it "allows spying on any method" do jake.sign_up(library) expect(library).to have_received.register_junior("Jake") end end """ Scenario: Invoking arbitrary methods Then spec file with following content should pass: """ruby require_relative 'student' describe Student do let(:library) { fake } it "allows calling any method with any parameters" do expect { library.foo library.bar("hello") library.baz(1, 2, 3, 4, 5) }.not_to raise_error end end """