What Is Double Method in Rspec For

Ruby: Rspec double confusion

You're close. Here's how to mock that call to Person.new:

First, let's make the Person and Product classes a bit more realistic...

class Person 
def default_number_of_products
Product.new.default_number
end
end

class Product
attr_reader :default_number

def initialize
@default_number = 3
end
end

Now for the Person tests that mock the Product class...

describe Person do
subject(:person) { described_class.new }

describe '#default_number_of_products' do
let(:product) { instance_double(Product, default_number: 42) }

before do
allow(Product).to receive(:new).and_return(product)
end

it 'returns 42' do
expect(person.default_number_of_products).to eq(42)
end
end
end

Had the code in Product executed, the call to person.default_number_of_products would have returned 3. Instead, this test spied on Product.new and returned a double in place of a real Product. So, when the code in person.default_number_of_products executes, it sees the double, which has a default_number of 42.

Finally, in your question above you mentioned that you thought that mocks should allow you to create one class without have to create the collaborators. That is a true statement. However, in the tests above, instance_double(Product, ...) actually creates a duck type from the real Product class. So, it would need to be defined. If you wanted to TDD this before creating the Product class, you could pass a string in place of the class name, like this:

let(:product) { instance_double('product', default_number: 42) }

HTH

What is the argument passed into RSpec's double method used for?

It sets a title for the double to be used in error messages.

#<Double "A Double"> received unexpected message :foo with (no args)

If you have multiple doubles, it will help you to figure out which one received an unexpected message.

In addition to the title, you can make your double respond in a predefined way to a method without using something like allow(double_x).to receive(:foo).and_return('bar') to set it up:

let(:double_x) { double("Double X", foo: 'bar') }
# double_x.foo
# => "bar"

The title is optional and can be left out.

RSpec - How to properly use doubles and stub methods on helper objects?

I usually do something like this.

let(:fake_service) { your double here or whatever }

before do
allow(SomeService).to receive(:new).and_return(fake_service)
# this might not be needed, depending on how you defined your `fake_service`
allow(fake_service).to receive(:process).and_return(fake_results)
end

Where's the official doc for RSpec's instance_double method that outline how you can configure the method's return value?

From the Yard documentation:

instance_double(doubled_class, stubs)

Parameters:

  • doubled_class (String, Class)
  • stubs (Hash) — hash of message/return-value pairs

is_happy: true will make the double return true when sent the the message is_happy.

RSpec has both the normal API documentation which is generated by Yard from the code and the guide style documenation that you have linked. Its quite common to have both in a well documented project since they serve different purposes.

Is there a way in RSpec to return the double object itself on doubles?

You can configure the messages in bulk via receive_messages:

relation = double(:relation, each_record: [record])
allow(relation).to receive_messages(in_batches: relation, active: relation)

There's also as_null_object which returns the double in response to arbitrary messages:

relation = double(:relation, each_record: [record]).as_null_object

relation.in_batches.active.each_record #=> [record]
relation.foo.bar.baz.each_record #=> [record]

How can I double variable within method in rspec rails

The problem with your test is that it doesn't test anything. The controller test should make a request to test the method get :foo!

About stubbing, in your case current_user method can be stubbed instead:

RSpec.describe TestController, type: :controller do
describe "#foo" do
it "should be passed" do
@specific_user = FactoryGirl.create(:user)
allow(controller).to receive(:foo!).and_return(true)
allow(controller).to receive(:current_user).and_return(@specific_user)
end
end
end

And yeah, in the controller test the controller instance can be accessed by calling controller method.

What also allows to set an instance variable in this controller:

RSpec.describe TestController, type: :controller do
describe "#foo" do
it "should be passed" do
@specific_user = FactoryGirl.create(:user)
allow(controller).to receive(:foo!).and_return(true)
controller.instance_variable_set(:@user, @specific_user)
end
end
end


Related Topics



Leave a reply



Submit