[rspec-users] Is there a way to run `let` once per context?

John Feminella johnf at bitsbuilder.com
Fri Jun 24 09:08:29 EDT 2011


>> Alternatively, should I just use before(:all) for this?
>
> Just use before(:all). That's what it is designed for, and it tells you that you have stuff to clean up in an after(:all) hook.

I was about to take your advice, when I discovered another problem:

======
RSpec.configure do |config|
  config.mock_with :rspec

  config.before(:each, :geocoding => nil) do
    Geocoding.stub(:client).and_return(Geocoding::StubGeoClient.new)
  end
end
======

Since the test-specific before-all hook runs first before the global
before-each hook, that means that the `expensive` operation now hits
an external geocoding service, which makes it take even longer. It
also makes tests fail because WebMock is running, and it prohibits
network connections you don't explicitly specify.

The fact that this is becoming obnoxious suggests that something else
is probably bad (e.g. maybe the `expensive` model should be changed to
be less expensive to create). I think I'll do that instead of trying
to go down this road further. Thanks for your help, David.

~ jf

On Fri, Jun 24, 2011 at 08:48, David Chelimsky <dchelimsky at gmail.com> wrote:
>
> On Jun 24, 2011, at 7:17 AM, John Feminella wrote:
>
>> hello,
>>
>> I have a monolithic test that looks like this:
>>
>> ======
>> describe Model do
>>  describe "#method" do
>>    let!(:expensive) { ... }
>>
>>    it "should do a lot of things" do
>>      expensive.should be_foo
>>      expensive.should be_bar
>>      expensive.should be_baz
>>    end
>>  end
>> end
>> ======
>>
>> I would like to refactor the large spec into smaller ones:
>>
>> ======
>>    it "should be foo" { expensive.should be_foo }
>>    it "should be bar" { expensive.should be_bar }
>>    it "should be baz" { expensive.should be_baz }
>> ======
>>
>> However, doing this slows down the tests a bit, because the
>> `expensive` method requires hitting the database.
>>
>> Suppose that I can guarantee that none of the tests or the methods
>> they call will be modifying the object returned by the `expensive`
>> method. Is there a way to tell RSpec to memoize the `expensive` result
>> across the context, and not just across an individual test run?
>>
>> Alternatively, should I just use before(:all) for this?
>
> Just use before(:all). That's what it is designed for, and it tells you that you have stuff to clean up in an after(:all) hook.


More information about the rspec-users mailing list