[rspec-users] Best practices for sharing state between story steps?

Jim Morris ml at e4net.com
Tue Sep 9 17:18:54 EDT 2008

Thanks for the hints, but I think I did point out I am not using Rails, I write Integration tests, 
that talk directly to the web application via HTTP running the full stack.

So Active record is not available neither are transactions for the database.

Sorry for the confusion.

If I were using Rails I would undoubtedly do it the way you suggest :)

Matt Wynne wrote:
> On 9 Sep 2008, at 19:52, Jim Morris wrote:
>> aslak hellesoy wrote:
>>> The debate seems to be whether step definitions should be stateful or 
>>> not.
>>> In practice this is achieved by setting one or more @variables in a
>>> step and reusing them in a different step - all within a scenario.
>> I think that is the debate, but I'd like to point out that there is 
>> always state between steps, it is just a matter of where it is being 
>> kept. In your example for instance most of the state is being kept in 
>> the database between steps (ie between Given an "active" site_user 
>> names "aslak" and he following steps.
>> (As a side question how do you clean up the database between tests, so 
>> the "state" from the previous Scenario doesn't affect the next 
>> Scenario?) In some cases I use a randomly generated record each time.
> I think the scenarios are each wrapped in a transaction, so (as long as 
> you're using the right type of database / tables) the slate should be 
> wiped clean between each one.
>>> Here is an example of a stateless scenario: (As a convention I'm
>>> "quoting" variables)
>> That is quite interesting, however as I pointed out above there is 
>> state between steps, in the database and in the response.
>> I actually do something very similar, with named resources in each 
>> step, however I find I still need to use variables between steps, here 
>> is an example... (Not rails)
>> Scenario: testing a pet
>>   Given I have a pet named "my dog"
>>   When I stroke "my dog"
>>   Then "my dog"'s health goes up
>> In the Given I create a pet named "my dog" in the database either 
>> directly or through the REST-ful API to my Web app, however in both 
>> cases I need the returned id of the created pet to make any further 
>> calls on it.
>> In the When clause I need to make an API call that pets "my dog", the 
>> API is POST stroke/345
>> So what I do is in the Given I assign the returned id of the new 
>> record to $petid, then in the When clause I do something like, 
>> $http_req.post("stroke", id => $petid).
>> Now I needed to carry that variable $petid around otherwise how would 
>> I be able to make the call in When.
>> Similarly when I want to check my pets health in the Then clause I 
>> still need that $petid, whether I check the value directly in the 
>> database or make an API call that returns my pets health.
>> I don't see anyway around keeping state in these cases.
>> Now I do clear that state ($petid= nil) in the before_scenario hook, 
>> so another scenario which may be written badly and not assign the 
>> $petid, won't succeeed due to a previously successful scenario.
>> I'd definitely be interested in better ways to do this though, as I 
>> hate passing global variables around (as I said in an earlier post I 
>> can't use @variable because the before_scenario does not seem to have 
>> access to the same scope as the scenario that is about to run). 
>> Although I think someone said each scenario has its own variables? I 
>> didn't notice that behavior.
> I've been thinking about this a bit, after reading Aslak's advice which 
> went contrary to my instincts. It seems like you could probably do 
> something like this instead:
> Scenario: testing a pet
>   Given I have a pet
>   When I stroke the pet
>   Then the pet's health goes up
> Because your Given step creates just one Pet instance, you can safely 
> refer to it as "the pet" in the other steps, and simply call 
> Pet.find(:first) in the step matcher.
> See?
> In a more complicated scenario:
> Scenario: testing a pet
>   Given I have two pets named "my dog" and "my cat"
>   When I stroke "my dog"
>   Then "my cat" should be pissed off
> Now your step matcher needs to refer to a particular pet, but can't it 
> just use the name as a key, since that will be unique within the set of 
> two Pet records you created in your Given step?
> When /I stroke "(.*)"/ |pet_name| do
>   Pet.find_by_name(pet_name).stroke
> end
> Does that make sense to you?
> cheers,
> Matt
> ----
> http://blog.mattwynne.net
> http://songkick.com
> In case you wondered: The opinions expressed in this email are my own 
> and do not necessarily reflect the views of any former, current or 
> future employers of mine.

Jim Morris, http://blog.wolfman.com

More information about the rspec-users mailing list