Reputation: 12916
I am working on some rspec tests now where one of my initialize parameters is a "foreign" class, meaning I have no clue where it comes from. It is injected from a framework I am using. In my code I need to utilize this object for various things, mostly/exclusively to call methods to pass data to this object (no data extraction).
Is it possible to completely mock an object so that I can verify that certain, undefined, methods are called.
#an example of what this object could look like
let(:my_obscure_object) { RSpec.complete_mock } #NOTE: This does not work
...
it "verify .whatever method is called" do
expect(my_obscure_object).to receive(:whatever).with(some_data)
my_class.work
end
it "verify .sub_whatever method is called" do
expect(my_obscure_object.sub_thing).to receive(:sub_whatever).with(some_data)
my_class.work2
end
The method I can think of currently to solve this is to make an object and stub every single possible method I might need, like this
#an example of a tedious method to solve my problem
let(:my_obscure_object) { Object.new }
before(:each) do
my_obscure_object.stub(:whatever) { nil }
my_obscure_object.stub(:whatever2) { nil }
my_obscure_object.stub(:whatever3) { nil }
my_obscure_object.stub(:whatever4) { nil }
my_obscure_object.stub(:whatever5) { nil }
ob = Object.new
ob.stub(:sub_whatever) { nil }
my_obscure_object.stub(:sub_thing) { ob }
end
...
it "verify .whatever method is called" do
expect(my_obscure_object).to receive(:whatever).with(some_data)
my_class.work
end
it "verify .sub_whatever method is called" do
expect(my_obscure_object.sub_thing).to receive(:sub_whatever).with(some_data)
my_class.work2
end
Is there any solutions to my problem?
Upvotes: 1
Views: 652
Reputation: 29399
You can create a test double which will accept all method calls using as_null_object
, as follows:
describe "SO example" do
#an example of what this object could look like
let(:my_obscure_object) { double("obscure").as_null_object }
let(:some_data) { 'foobar'}
it "verify .whatever method is called" do
expect(my_obscure_object).to receive(:whatever).with(some_data)
my_obscure_object.whatever(some_data)
end
it "verify .sub_whatever method is called" do
expect(my_obscure_object).to receive_message_chain(:whatever, :sub_whatever)
my_obscure_object.whatever.sub_whatever
end
end
Note that the receive_message_chain
method is only available as of RSpec 3.0.0.beta2 available from github and does not allow you to specify any expected argument values. You can rewrite that expectation using individual test doubles if you want to use an older version of RSpec or specify the arguments passed.
Upvotes: 3