[rspec-users] before(:all) and nested contexts

David Chelimsky dchelimsky at gmail.com
Thu Jul 9 10:40:13 EDT 2009


On Thu, Jul 9, 2009 at 9:37 AM, Daniel Tenner<daniel.rspec at tenner.org> wrote:
>> 2) Is it your goal to call "some_expensive_operation" once and only once?
>
> Yes, exactly. In the case of the project archival spec, creating a project,
> archiving it, and then unzipping it to a temporary location to look at what
> was archived is a process that takes about 3 seconds on my machine. Since
> archival isn't something people will be doing live on the site, speed is not
> an issue from a user point of view. However, there's about 25 specs (in
> about a dozen sub-contexts) examining the zip output... multiply that by 3
> seconds each, and that takes more time to run than all the other specs
> combined!
> I have actually managed to get this done using the method described in my
> blog post @
> http://www.swombat.com/getting-rspec-beforeall-and-nested-contexts-w , but I
> have to admit it's a bit hackish.
> David - ":apply_to_nested => false" seems like a great way to do it, but I
> understand why you'd want to get the refactoring out of the way first. With
> my temporary hack in place, I can wait.

My message about refactoring was back in January :) If you're
interested in supplying a patch I'd be interested in accepting it.


> Thanks,
> Daniel
> On Thu, Jul 9, 2009 at 3:22 PM, Zach Moazeni <zach.lists at gmail.com> wrote:
>>
>> Rereading your original email, I'm thinking I may not have entirely
>> understood your situation.
>>
>> 1) Looks like you've already defined the "some_expensive_operation" (but
>> that's minor)
>>
>> 2) Is it your goal to call "some_expensive_operation" once and only once?
>>
>> On Jul 9, 2009, at 10:18 AM, Zach Moazeni wrote:
>>
>>> Hey Dan,
>>>
>>> 1 approach you could do is define a method within the outer describe that
>>> is called within the inner describe and within each test not contained by an
>>> inner describe.
>>>
>>> describe "Some functionality" do
>>>  it "should do something" do
>>>   @variable = some_expensive_operation
>>>   @variable.should do_something
>>>  end
>>>
>>>  describe "in a specific context" do
>>>   before(:all) do
>>>     @variable = some_expensive_operation
>>>   end
>>>
>>>   it "should do another thing" do
>>>     @variable.should do_another_thing
>>>   end
>>>  end
>>>
>>>  def some_expensive_operation
>>>   p "in here"
>>>  end
>>> end
>>>
>>> (also uploaded to http://gist.github.com/143693)
>>>
>>> My solution is to unDRY the subcontext's preconditions. I have pretty
>>> strong opinions about DRYing up specs at the cost of grokability.
>>>
>>> On Jul 9, 2009, at 6:40 AM, Daniel Tenner wrote:
>>>
>>>> Hi all,
>>>>
>>>> Like everyone (?), I use nested contexts to keep my specs well organised
>>>> and tidy.
>>>>
>>>> However, I have a problem. I have various sets of specs that needs to
>>>> perform very time-expensive operations to set up the fixtures that will be
>>>> examined in the tests. Two specific examples: testing access control logic
>>>> (requires creating a whole tree of items to verify the correct access level
>>>> against each item), and project archival (which creates a project, fills it
>>>> with test data, archives/zips the project contents, then unzips them for
>>>> examination).
>>>>
>>>> I tried using before(:all) to set up those costly fixtures, however I
>>>> hit upon a feature of rspec that made that less than successful:
>>>>
>>>> When using before(:all) along with nested contexts, rspec actually
>>>> re-runs the before(:all) before each sub-context. So if, like me, you have
>>>> your specs neatly organised in sub-contexts, the before(:all) is actually
>>>> re-run many times.
>>>>
>>>> Interestingly, when a before(:all) is run in the root context, rspec
>>>> does not actually remove the data from the database when re-running the
>>>> before(:all). "Great," I then thought, "I can just detect whether the data
>>>> is created and decide whether or not to create the objects on that basis".
>>>> Not so fast, though: Rspec may not clobber the database, but it does clobber
>>>> instance variables. In the case of the access control test, there's about 40
>>>> different instance variables, so keeping track of them all manually in some
>>>> global variable outside of rspec would be messy to say the least...
>>>>
>>>> So my question is, is there any workaround for successfully using
>>>> before(:all) and nested specs, so that code like the following works and
>>>> doesn't run the expensive operation more than once:
>>>>
>>>> describe "Some functionality" do
>>>>  before(:all) do
>>>>   @variable = some_expensive_operation
>>>>  end
>>>>
>>>>  it "should do something" do
>>>>   @variable.should do_something
>>>>  end
>>>>
>>>>  describe "in a specific context" do
>>>>   it "should do another thing" do
>>>>     @variable.should do_another_thing
>>>>   end
>>>>  end
>>>> end
>>>>
>>>> Worth noting that I'm quite happy to give up the ability to have before
>>>> blocks in the sub-contexts in order to ensure that the expensive operation
>>>> is only run once...
>>>>
>>>> Your thoughts most welcome... (including, perhaps, telling me that I'm
>>>> Doing It Wrong)
>>>>
>>>> Daniel Tenner
>>>> http://www.woobius.com
>>>> http://danieltenner.com
>>>> _______________________________________________
>>>> rspec-users mailing list
>>>> rspec-users at rubyforge.org
>>>> http://rubyforge.org/mailman/listinfo/rspec-users
>>>
>>> --
>>> Zach Moazeni
>>> http://simplechatter.com
>>>
>>>
>>>
>>
>> --
>> Zach Moazeni
>> http://simplechatter.com
>>
>>
>>
>> _______________________________________________
>> rspec-users mailing list
>> rspec-users at rubyforge.org
>> http://rubyforge.org/mailman/listinfo/rspec-users
>
>
> _______________________________________________
> rspec-users mailing list
> rspec-users at rubyforge.org
> http://rubyforge.org/mailman/listinfo/rspec-users
>


More information about the rspec-users mailing list