Question

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?

Was it helpful?

Solution

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
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top