[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