The coding standard that I'm working in specifies that a group of specs testing a function should have a subject that is the function being called. It looks like this:
define User do
context :foo do
let(:user) { FactoryGirl.create(:user) }
subject { user.foo }
it { ... }
end
end
The typical use of the subject
block is to instantiate the Class that you are testing:
define User do
subject { FactoryGirl.create(:user) }
it { ... }
end
The intended effect of our style guide is that we have a different subject block for each method that is being tested. Is this slowing down our tests? If we used subject
in the typical manner, would we benefit from built in memoization or other speedups from only having one subject block per Class?
Asside:
I've run into one case where our style does not work. When using any_instance.should_receive
you cannot follow our style guide or the spec will always fail. Instead, you need to use a more traditional approach where subject
is the object that you are testing and you call the method on it in your spec.
# passing spec
define Foo do
before { Bar.any_instance.stub(:baz) }
subject { FactoryGirl.create(:foo) }
it "bazzes Bars" do
Bar.any_instance.should_receive(:baz)
subject.baz_the_bars
end
end
# spec follows style guide but fails
define Foo do
before { Bar.any_instance.stub(:baz) }
let(:foo) { FactoryGirl.create(:foo) }
subject { foo.baz_the_bars }
it "bazzes Bars" do
Bar.any_instance.should_receive(:baz)
subject
end
end
class Foo
has_many :bars
def baz_the_bars
bars.collect do |bar|
bar.baz
end.count(true)
end
end
Are there any other gotcha's I should look out for with this style?
subject
is lazily created, per-test, and scoped to the context
/ describe
, just like let
. There shouldn't be any extra overhead to them.
I don't personally like the style you show, but I've done something similar when I have very complicated (or just big) data objects that are returned from a method.
describe "A thing" do
subject(:foo) { FactoryGirl.create(:foo) }
# A very complicated object from this method
describe "the result of calling frob" do
subject(:result) { foo.frob }
it { should be_active }
it { should be_alive }
end
end