Reusing story snippets

I find myself doing this:

Scenario “logged in user visiting the home page” do
Given “A logged in user” do
a_logged_in_user
end

When “…”
Then “…”
end

The a_logged_in_user method is a helper method in helper.rb which sets
up the state so that the user can browse the website.

Later in the story of course, I can just do 'Given “A logged in user”
and it will get the previous definition.

Is there any way to avoid that duplicated Given call at the top of
almost every story?

Mikel

On Sat, Jun 14, 2008 at 5:03 AM, Mikel L. [email protected]
wrote:

The a_logged_in_user method is a helper method in helper.rb which sets
up the state so that the user can browse the website.

Later in the story of course, I can just do 'Given “A logged in user”
and it will get the previous definition.

Is there any way to avoid that duplicated Given call at the top of
almost every story?

If it’s implicit in almost every story, just call the helper in the
first step of your scenarios. This might be an issue if you’re
striving to recycle steps, but otherwise it works perfectly well. If
the story obviously requires authentication, why bother specifying it?

Maybe others will see it differently, but I omit a lot of the
“scaffolding” preconditions when it’s clear from context:

Given a user editing their account details

Of course they have to be logged in for that. I may write a single
scenario that shows users can’t get to their account details page
without being logged in, but the rest can happily just imply it:

Given(“a user editing their account details”) do
a_logged_in_user
browse_to(‘account details page’)
end

k

On Jun 14, 2008, at 5:03 AM, Mikel L. wrote:

I find myself doing this:

Scenario “logged in user visiting the home page” do
Given “A logged in user” do
a_logged_in_user
end

When “…”
Then “…”
end

Things have evolved a bit since Story Runner first came out. The
approach you are using here is what we call in-line steps, and was the
only option back then.

You can now use disconnected steps in both plain text and Ruby:

require ‘steps/visitors’

Story “logged in users see more stuff”, %(
As a registered user
I want to see more stuff than non-registered users
So I can feel like I’m getting some benefit in return for giving
up my personal information
), :steps => :visitors do
Scenario “logged in user visits home page” do
Given “I am logged in as David”
When “I visit the home page”
Then “I should see the message ‘Welcome David’”
end
end

in steps/visitors

steps_for :visitors do
Given “I am logged in as $name” do |name|
# create a user w/ name and log in as that user
end

When “…”
Then “…”
end

This approach really cleans up the story code leaving the informative
bits while hiding the redundant detail.

HTH,
David

Along similar lines is there a way to do the equivalent of
before(:all) and after(:all) or after(:each) in stories?

Basically I have a similar situation as above, but I need to make sure
the user is logged out after each scenario. or that the user is logged
in once at the start of all scenarios then logged out after them
regardless of errors etc.

Thanks

I’m not using Rails, I am doing end to end integration testing talking
to the server via net/http, so RailsStory is not involved.

I think the listeners may do it, I can use story_started like
before(:all) and story_ended like after(:all) which will be great,
presuming story_ended is always called even after a failure.

However I am missing the place where that listener gets registered, I
am using the…

Story “description”, %{…}, :steps_for => steps do
Scenario “sdsdsd” do

end
end

syntax, so where is the listener set?

Thanks

Ahh ok think I found it…

In my test file at the start…

class MyListener
def method_missing sym, *args, &block
# ignore all messages you don’t care about
end

def story_started(title, narrative)
puts “…Started story #{title}”
end

def story_ended(title, narrative)
puts “…Ended story #{title}”
end
end

Spec::Story::Runner.register_listener(MyListener.new)

Then I define my steps using StepGroup.new

Then the Scenarios

It seems to work although not very intuitive :slight_smile:

I’d prefer a before(:all) and after(:all)

Reordered your posts so my comments make sense (we prefer to avoid
top-posting - even though I sometimes violate that myself :slight_smile: ).

On Jun 16, 11:58 pm, Jim M. [email protected] wrote:

I’m not using Rails, I am doing end to end integration testing talking
to the server via net/http, so RailsStory is not involved.

Cool. Are you talking directly through ruby constructs or through a
browser tool like selenium?

I think the listeners may do it, I can use story_started like
before(:all) and story_ended like after(:all) which will be great,
presuming story_ended is always called even after a failure.

Yep.

Thanks

On Tue, Jun 17, 2008 at 2:28 AM, Jim M. [email protected] wrote:

puts “…Started story #{title}”
end

def story_ended(title, narrative)
puts “…Ended story #{title}”
end
end

Spec::Story::Runner.register_listener(MyListener.new)

Yep. That’s the right way.

Then I define my steps using StepGroup.new

You can just use the steps_for method and it’ll still work.

Then the Scenarios

It seems to work although not very intuitive :slight_smile:

I’d prefer a before(:all) and after(:all)

I’m not with you on that, but I’m open :slight_smile: We could solve the OP’s
problem with something like this:

Before Each Scenario:
Log in as admin

Scenario: editing private data

Before Each Scenario would match a Given step definition “Log in as
$role” or something like that.

I’m just not sure this really heads us down the right path. Next thing
you know we’ll have Before Story, After Each Scenario, After Story,
etc and the stories are going to start looking less and less like
stories and more and more and more like code, at which point you
should be using example groups instead :slight_smile:

Anybody else have opinions about that?

Cheers,
David

David C. wrote:

Cool. Are you talking directly through ruby constructs or through a

def method_missing sym, *args, &block
end
You can just use the steps_for method and it’ll still work.
problem with something like this:
I’m just not sure this really heads us down the right path. Next thing

I really don’t like the idea of having a “Before Each Scenario” or
similar construct. I have already seen abuses of the story runner where
the stories look too much like code/examples. I think adding such
language to the story runner would really hurt and confuse the original
intent of stories. I’m not questioning whether such an addition would
be helpful, I think it would and I may at times use it… but IMO it
would only be helpful to the developers point of view and I don’t see it
really adding much value to the stories. If someone can offer an
example where they think such language would help the stakeholder I
would be interested but to me it is starting too look too much like
examples.

Like Kyle said in a previous post, I think a better way to handle these
situations is to rely on the fact that having an admin be logged in is
somewhat implicit in the story and that the implementation can be
handled under the covers, so to speak, with helper methods within the
steps. This of course will require you to call the same helper method
for all of your first Given steps. So I guess this is where the pain
point is… but it doesn’t seem to be a big one most of the time.

The Listeners are good for application-wide/story suite wide setup and
cleanup, like databases as such. Placing the login of an admin into a
listener would obviously be overkill unless all of your stories involved
an Admin being logged in. What people seem to asking for is more
control over the granularity of which stories a particular listener
effects. Say, for example you have a set of stories that all require
that an Admin account to exist with certain permissions and that the
admin is logged in. What if you could define your AdminSetupListener
and then hook it into the runner for your stories like so:

with_steps_for(:admin_section, :webrat).and_listeners_for(:admin_setup)
do
run_story(File.expand_path(FILE))
end

This could provide the setup/teardown capabilities for a certain set of
stories without polluting the Story language.

Does that make sense what I’m suggesting? I’m not sold entirely on it
myself. It seems to add yet another layer of abstraction to help DRY up
the steps and in so doing spreads the story’s executable code throughout
even more files. This could hurt maintainability so I think the use of
this could also be abused… but if people want more granular control in
there setup and teardown with the Stories I would vote for an option
like this instead of placing it in the actual Story language/parser
itself.

I hope most of that makes sense. :slight_smile:

-Ben

On Jun 17, 2008, at 10:41 AM, Ben M. wrote:

Yep.

end

I’d prefer a before(:all) and after(:all)

Anybody else have opinions about that?
addition would be helpful, I think it would and I may at times use
helper methods within the steps. This of course will require you to
stories that all require that an Admin account to exist with certain
of stories without polluting the Story language.
I hope most of that makes sense. :slight_smile:
Perfect sense to me :slight_smile:

Cheers,
David

On Jun 16, 2008, at 6:18 PM, Jim M. wrote:

Along similar lines is there a way to do the equivalent of
before(:all) and after(:all) or after(:each) in stories?

Basically I have a similar situation as above, but I need to make sure
the user is logged out after each scenario. or that the user is logged
in once at the start of all scenarios then logged out after them
regardless of errors etc.

Each scenario is run in its own instance of RailsStory, so it’s got a
new session (IntegrationSession). So you should get this isolation
implicitly.

There are callbacks you can use if you create and register a listener,
but they won’t have access to the same scope that exists inside the
steps. Here’s how you do it:

class MyListener
def method_missing sym, *args, &block
# ignore all messages you don’t care about
end

def run_started(num_scenarios); end
def story_started(title, narrative); end

etc
end

See
http://rspec.info/rdoc/classes/Spec/Runner/Formatter/Story/PlainTextFormatter.html
, which implements all the callback methods (we need better docs for
it, but everything is there - don’t use collected_steps though - that
should really be marked nodoc).

Cheers,
David

Hi, Not top posting (although I prefer it :wink:

Cool. Are you talking directly through ruby constructs or through a
browser tool like selenium?

I have a helper that makes posts and gets and deletes and puts
directly to the server which is implements a mostly REST-ful API and
written in Java.
I use an Hpricot based matcher that implements have_xpath to test the
XML that is returned for each API call.

It is a true integration test that can test the server running locally
or the staging server running at the Colo.

I was using (and do use) Example groups for most of my integration
tests, however I started using Programmatic Stories (not plain text
stories) for a number of reasons.

Firstly I prefer it looking like code so I put the whole thing in a
single file…

steps = Spec::Story::StepGroup.new do |define|
define.given(“user has empty bag”) do
etc

Story “test user can create, get and delete bags”,…, :steps_for =>
steps do
Scenario " create bag"…
Scenario “get bag…”
Scenario “delete bag…”
etc

I prefer this because I am a programmer, it keeps things in one place
and makes it easy to maintain. I don’t have stakeholders so plain text
stories are just another layer for me. Although I would use them if I
did have laymen stake holders. I am testing a REST-ful AJAX like API
to a webservice, that is used by programmers, so my stakeholders would
be/are programmers and again prefer programmatic code rather than
plain text stories.

The reason I like Stories in this case, rather than Examples, is that
for integration testing, I can test all the edge cases for the API in
the most DRY-full way. The steps are coded once and I can just define
very thin Scenarios that test different parameters being passed in and
exercise all those edge cases where parameters are bad or left out
etc. Doing this the “old” way using Example groups was not at all DRY,
but worked pretty well. (Although Example groups with tons of helpers
maybe considered equivalent).

The thing I have learned about all these BDD, TDD, XP, AGILE things
is to be flexible and use the best tools and practices for the job.
Being single minded and saying programmers can’t use stories they are
only for stake holders means we lose a good tool! (Not that I am
accusing anyone of being single minded :wink:

Back to why I want/need these global setup/teardowns… And BDD
purists stop reading now :wink:

When doing integration testing of a remote server this way you know
all the tests need to have a login and a valid Sessionid in the
cookie. You don’t want to login/logoff every Scenario because it is
SLOOOW. Logging in and out does not test the API other than the login
and logoff API and that of course has been tested once already. It is
not DRY to have to call login and logout in every Given, plus you need
it to logout even if the tests fail. And lastly (Shudder) some tests
have to rely on the state left by a previous test, hence the session
id needs to be the same, for a group of scenarios like add a resource,
modify the resource then delete the resource are best done as separate
Scenarios, relying on the previous Scenario. It would be slow and not
DRY to have to test add, then test add, modify, then test add, delete,
it is better to have Scenario add, Scenario modify, Scenario delete. I
know this flys in the face of SOP, but it is DRY and it is efficient
(ie faster) and it works!

I hope that explains where I am coming from and how I (Mis-)use these
excellent tools you have written.

Thanks
Jim

Yep thats exactly the case, an entire Story specific setup/teardown
for the Given, When Language API

Scenario setup is obviously done in the Given, although a way to clean
up if the spec fails would be nice.

The listener works fine for this, its just not a very intuitive way of
setting things up. However I could easily add some sugar
to my spec_helper that does the listener setup for me, basically just
wrap this…

class MyListener
def method_missing sym, *args, &block
# ignore all messages you don’t care about
end

def story_started(title, narrative)
puts “…Started story #{title}”
end

def story_ended(title, narrative)
puts “…Ended story #{title}”
end
end

Spec::Story::Runner.register_listener(MyListener.new)

Jim M. wrote:

I use an Hpricot based matcher that implements have_xpath to test the
single file…
etc
for integration testing, I can test all the edge cases for the API in
only for stake holders means we lose a good tool! (Not that I am
not DRY to have to call login and logout in every Given, plus you need
I hope that explains where I am coming from and how I (Mis-)use these
excellent tools you have written.

Thanks
Jim

Ahh, I forgot that the original post was not dealing with plain-text
stories. From what I understand now, you prefer the Given, When, Then
language for your certain situation and want more flexibility to help
DRY these programmer-only stories. That makes a lot more sense now that
I’m reminded of the context, thanks. :slight_smile:

When testing all the different edge cases based on different parameters
passed in the URL I find that nested describes (example groups), like
you mentioned, provide a good way to DRY up specs. The spec-docs also
lend themselves well to readable docs for programmers wanting to use the
API. When using the story framework to do this are you suggesting that
a story be able to have setup/teardown and also have specific
setup/teardown for individual scenarios? Or are you just suggesting
setup/teardown for an entire story (and not the scenarios)?

That sounds reasonable and useful, so I hope I didn’t come off sounding
like I thought your idea was a poor one. In the context of plaintext
stories I was thinking it would be a dangerous way to go down unless the
language helped the stakeholder. Having more flexible setup/teardown
for stories in general seems like a good idea that would help everyone
though.

-Ben

Ok here is my sugar, put in spec_helper.rb

require ‘rubygems’
require ‘spec’
require ‘spec/story’

simulate before(:all) and after(:all) for stories

class MyListener
def set_before(&block)
@before= block
end

def set_after(&block)
@after= block
end

def method_missing sym, *args, &block
# ignore all messages you don’t care about
end

def story_started(title, narrative)
@before.call if @before
end

def story_ended(title, narrative)
@after.call if @after
end
end

def setup_listener(listener)
unless $my_listener
Spec::Story::Runner.register_listener(listener)
$my_listener= listener
end
end

def before_story(&block)
listener ||= MyListener.new
listener.set_before(&block)
setup_listener(listener)
end

def after_story(&block)
listener ||= MyListener.new
listener.set_after(&block)
setup_listener(listener)
end

Use it in your story ruby file thusly…

require File.join(File.dirname(FILE), “spec_helper”)

execute this code before story runs

before_story do
#stuff
end

execute this code after the story runs

after_story do

more stuff

end

I’m sure it could be cleaner!

Hi Dan,

Thanks for the analysis. Yes I am a strong proponent of using the best
tools for the job, even it means bending the rules.

I like the view of the stakeholder being another program, it certainly
will make the phrasing of the header easier as I was struggling with
that.

One other question: is there a way you can programmatically set the state of
“logged in” without having to actually log in via the app?

In this case of a pure integration test where the server is usually
remote there is no easy way to fake a login. I am exercising the
actual WEB service API as if I were a real client. I have plenty of
Unit tests using Mocks for testing the server at the method level of
course.

…For the Givens I
think it’s perfectly acceptable to just “make it so”. Whether that’s putting
some value in a session or shoving some data in a table

I also do that especially for setting up data in a database before
running the test, the trick is to be able to clean the database from
whatever state it was in previously.So I have things like “Given the
database has no entries” which will truncate the tables etc. But these
kinds of tests usually have to run locally as the database is
generally not accessible remotely through the various firewalls etc.

Setting up Sessions though means you actually need to go through the
various states to get the session setup, rather than plugging
something into a session, which would be more of a functional test and
not an integration test.

I have to say that using the steps and scenarios model for integration
testing is very DRY and much easier to write than doing it with
Example groups.
When I get some time I’ll write a blog entry on how I use rspec,
stories and various helpers to do this integration testing.

Thanks for the feedback.

The bottom line here is in understanding who is the stakeholder for this
story - i.e. who cares about it, who will read it and who wants to know
when
it goes wrong.

It seems to me you are using the construct of scenarios to describe
machine
interactions: the request and response of service invocations. In this
case
the stakeholder is actually another (client) application so it’s
appropriate
to change the rules a bit.

As someone else said (or it might have been you!), the point of any
agile
process is to adapt to the context and help you get work done, not to
adhere
to a rigid set of rules. It looks to me like you’ve found a solution to
your
specific situation, which is a trade-off between the Rule of Idempotency
(all scenarios should be idempotent, i.e. rerunnable) and the Rule of
Independence (scenarios should be runnable in any sequence) on the one
hand,
and the annoyance of having to log in for each scenario on the other.

As David said, having story-level setup is a smell, but if you go in
there
with your eyes (nose?) open and you understand the trade-offs then you
should be ok.

fwiw I would probably define a separate Listener for each type of story
setup/teardown that is named for why it’s there, rather than a generic
before/after story thing that I attach blocks to. So in this instance I
would have a LoginOnceBeforeEachStoryListener.

One other question: is there a way you can programmatically set the
state of
“logged in” without having to actually log in via the app? For the
Givens I
think it’s perfectly acceptable to just “make it so”. Whether that’s
putting
some value in a session or shoving some data in a table. It’s only the
When
steps that should be duty bound to operate the app like a regular user,
because that’s the behaviour you are exercising. If so you could have a
super-fast “Given $user is logged in” step that runs at the start of
each
scenario.

Cheers,
Dan

2008/6/18 Jim M. [email protected]: