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

Thanks,

Daniel

On Thu, Jul 9, 2009 at 3:22 PM, Zach Moazeni <zach.li...@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@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@rubyforge.org
> http://rubyforge.org/mailman/listinfo/rspec-users
>
_______________________________________________
rspec-users mailing list
rspec-users@rubyforge.org
http://rubyforge.org/mailman/listinfo/rspec-users

Reply via email to