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

David Chelimsky dchelimsky at gmail.com
Fri Jun 24 09:15:16 EDT 2011


On Jun 24, 2011, at 8:08 AM, John Feminella wrote:

>>> 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.

You can resolve this using a shared group:

http://relishapp.com/rspec/rspec-core/v/2-6/dir/example-groups/shared-examples
http://relishapp.com/rspec/rspec-core/v/2-6/dir/example-groups/shared-context

> 
> 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).

That's definitely worth investigating :)

> I think I'll do that instead of trying
> to go down this road further. Thanks for your help, David.

y/w

Cheers,
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.
> _______________________________________________
> rspec-users mailing list
> rspec-users at rubyforge.org
> http://rubyforge.org/mailman/listinfo/rspec-users

Cheers,
David





More information about the rspec-users mailing list