When writing code that depends on another class, we sometimes like to stub out the dependency. This can result in test examples that are hard to read and full of details that aren't relevant to the actual test.
it "does something" do
dependency = double(:dependency)
allow(dependency).to receive(:foo).with(:bar).and_return(:baz)
allow(Dependency).to receive(:new).and_return(dependency)
SomeClass.new.some_method
expect(dependency).to have_received(:foo).with(:bar)
end
We could increase the readability of this spec by extracting the setup into a method.
it "does something" do
dependency = stub_dependency
SomeClass.new.some_method
expect(dependency).to have_received(:foo).with(:bar)
end
def stub_dependency
dependency = double(:dependency)
allow(dependency).to receive(:foo).with(:bar).and_return(:baz)
allow(Dependency).to receive(:new).and_return(dependency)
dependency
end
Now the details of the stubbing that are not specific to the test are moved away to somewhere more helpful. On top of this benefit, we can now share the setup between tests.
The next step would be to make the stubbing more readable by using #tap
. #tap
allows us to invoke side-effects on an object before returning the original object.
def stub_dependency
double(:dependency).tap do |dependency|
allow(dependency).to receive(:foo).with(:bar).and_return(:baz)
allow(Dependency).to receive(:new).and_return(dependency)
end
end
Using some well-named methods and #tap
we can make our tests a little bit happier.
Nice tip! 🤩