On 15 Mar 2009, at 16:52, Ben Mabey wrote:


I know what you mean, and it would certainly make for nice readable scenarios. My worry is how maintainable the steps would be in the long run. I'm used to seeing steps like this:

Given /the Policy has a secondary risk/ do
 Policy.count.should == 1
 policy = Policy.first
 policy.secondary_risk = true
 policy.save
end

Which are pretty explicit and leave no room for accidental abuse. What the OP suggested would give you something more like this:

Given /a Policy/ do
 @it = Factory(:policy)
end

With /a secondary risk/ do
 @it.secondary_risk = true
 @it.save
end

I dunno actually. Now I type it out it doesn't seem so bad :)


As previously mentioned in the thread another way to phrase this is with step tables. Here is the code I use:

http://gist.github.com/59007 (related blog post: 
http://www.benmabey.com/2009/02/05/leveraging-test-data-builders-in-cucumber-steps/)

I have been using instance variables in my steps (but naming them after the model, i.e. @policy) but Matt's DB solution is nice in some respects. Both ways fall apart when you have multiple polices, but in that case you should probably be passing in the name or some other identifying aspect of the model. Anyways, it seems like a pattern is emerging on how to carry state to other steps when you have to. I was bored so I combined both approaches:

module ObjectLocators

def the_policy
  if @policy
    @policy
  else
    case Policy.count
    when 0
raise "There is no @policy variable defined and no policy in the DB! Establish state in previous step or create a new policy."
    when 1
      Policy.first
    else
raise "There are multiple policies in DB and no @policy variable set! Please disambiguate the state in previous step."
    end
  end
end

end


World { |world| world.extend(ObjectLocators) }

(this code is here: http://gist.github.com/79470)

Like I said, I was bored and haven't really tried this. I don't know if I even like it, but I thought extracting out the patterns would be useful. You could leverage factories just as I do in my previous gist to provide locator (locater?) for all of your models.

We have some very similar code deep in the bowels of Songkick's features folder that is a little scrappy, but does help us solve this problem quite nicely.

Basically there's a regular expression that matches on phrases of the following form:

  the Widget
  the Widget "Foo"
  "Foo"

So you can use that in your step matchers like this:

  When /I delete (#{THE_THING})/ |identifier|
    thing_to_delete = identified_model(identifier)
  end

If you want to remember something just by the "Foo" label, you have to throw it into a collection, imaginatively named 'stuff', as you do so:

  stuff["Foo"] = Factory(:widget, :name => "Foo")

As I say it's a little scrappy as it's something we threw together ages ago and haven't really felt the need to revisit, but hopefully it will give someone some ideas:
http://gist.github.com/79496

Matt Wynne
http://blog.mattwynne.net
http://www.songkick.com

_______________________________________________
rspec-users mailing list
[email protected]
http://rubyforge.org/mailman/listinfo/rspec-users

Reply via email to