[rspec-users] stepping across features

Zach Dennis zach.dennis at gmail.com
Wed Dec 10 11:36:01 EST 2008

On Mon, Dec 8, 2008 at 11:56 AM, James Byrne <lists at ruby-forum.com> wrote:
> Andrew Premdas wrote:
>> TIp: When writing the step don't use  - visits "/invoices/new" - use
>> visits "invoice_new_path". Use named routes and let the routing names
>> REST and resources define where you go, and think about what you want
>> to implement
> This advice is really helpful.  I was reading the section on routing in
> "The Rails Way" last night, and it came to me that perhaps I had
> overlooked the essence of what I was really trying to accomplish.  That
> I was so fixated on the code yet to be produced at the detail level that
> I had missed the boat with respect to how the users would treat the
> application as a whole.  I concluded that I really needed to see the new
> application, and the features that I had to write, in terms of
> resources.  Then, given the resource name, the requisite information
> would be exposed.  This in turn would expose the requirements needed to
> assemble that information from data, and from those assembly
> requirements would come the code requirements.
> However, I was, until I read your reply, still thinking in terms of
> "/application/clients/:myclient/workorders/:id/charges/:billable"
> instead of
> client_workorder_charges_path(@client, at client.workorders,"billable") or
> however that is supposed to be expressed.
>> If you now deal with your charges, you will probably get to the stage
>> very quickly where you can't avoid clients. So then you do the very
>> simplest general thing for clients.
> It is impossible to undo the past.  We have already invested a
> considerable amount of energy and time into determining how we wish to
> express the concept of a client as a transient role of some persistent
> entity rather than as an artifact in itself.  But, that said, I am
> beginning to see that this can be set aside in the early stages.
>> Finally every time you find that the baby step you are taking is
>> actually more like a giant leap (or actually anything other than
>> the smallest of steps) STOP!  Then start again questioning what
>> is not central and what is not specific.
>> HTH
> Very helpful.  I expect that as I gather my wits regarding BDD that this
> advice will prove even more valuable.
> I tried a little bit of this out on one of the end users and I was
> surprised at the responses that I obtained.  In consequence, this is
> what I contemplate beginning with.
> Feature: A web based business application
> In Order To: Conduct Business
> Any Authorized User
> Should Access the Business Application via http
> To reduce costs
>  Scenario: The Application has a home page
>    Given an application accessible by http
>      And I am not signed in
>    When I browse to the url "/" on the application host
>    Then I should see a welcome message
>      And I should see a sign on request message
>      And I should see a sign on link
>      And I should see a contact us link
>      And I should see ...

This scenario is mixing what should be in a view spec with what should
in a scenario. For example, I think your scenario wants to be
"Anonymous visitors are welcomed to the site"
   Given I am an anonymous visitor
   When I browse to "/"
   Then I should see the welcome message: Howdy hey guy!

All of the other "I should see" steps you have don't really have
anything to do with the goal of welcoming the visitor to the site.
IMO, these are candidates for view specs since they are ensuring the
lower level details of certain pages are intact.

>  Scenario: The Application has a sign on page
>    Given I am on the home page
>      And I am not signed in
>    When I select the sign on link
>    Then I should see the sign on page
>      And the protocol should be https
>      And I should see a text entry for user name
>      And I should see a text entry for password
>      And I should see a sign on action selector

This scenario has the same problem. If you just have a scenario for
signing on (in) to the site wouldn't that force you to build a sign on
page for that to work?

>  Scenario: User Signs On Successfully
>    Given I am on the sign on page
>      And I am not signed in
>      And I have a user named "myuser"
>      And the user named "myuser" has a password of "myuserpassword"
>    When I provide a user name "myuser"
>      And I provide a password "myuserpassword"
>      And I select the sign on action
>    Then I should see a sign on success message
>      And I should see the users home page

How about....

    Given there is a user with the login 'myuser' and password 'mypassword'
    When I sign in to site with the login 'myuser' and the password 'mypassword'
    Then I should see the success message: You've signed in!

It makes it so much clearer IMO. This makes scenario communicate what
is valuable, and leaving out the additional clutter. Leave the lower
things like "filling in text fields" to the step definition
themselves. In your steps, communicate the what you're doing, and
leave the how you're doing it to the step definitions.

For example, you're signing/logging in. That's the what. The how is
filling in two text fields and clicking a button.

>  Scenario: User Sign On Fails - wrong password
>   ...
>  Scenario: User Sign On Fails - no such user
>   ...
>  Scenario: User Sign On Fails - more than 3 attempts in 20 seconds
>   ...
> Then we have identified a new feature, the user home page.  Also, one
> can foresee that additional scenarios are required, like "User Signs in
> >From a Secured Resource" where following a successful sign in the user
> is redirected back to the resource that they originally requested.

I don't think the "user home page" is a feature, but I bet there is
something on the home page that makes it valuable. What is that? That
is most likely your feature. When writing that feature and its
scenarios don't focus on the user home page. Focus on what's really
valuable. If there are things that need to be on the user home page
which are tedious details that don't really pertain to the feature,
then use a view spec.

For example, in our application we always show a navigation partial
for every page. Based on what part of the site you're in it will show
a different partial, ie; "fiscal/navigation", "hierarchy/navigation",
"operations/navigation", etc. Using features/scenarios to ensure every
page rendered the right navigation is the wrong place to do it. So we
wrote some shared examples...

  shared_examples_for "a page that has fiscal navigation" do
     # ...

Then we'd write view specs that used these shared examples to ensure
the tedious details of the page were taking care of.
Features/scenarios will cover most of the common things like clicking
major navigational links, filling out and submitting forms, etc.
However, webapps usually have a bunch of other components which may
not be linked to "doing" something, or there may be more than one
path, or things may need to show up on more than one page.

When you need to add something like this to the UI that doesn't fit in
a scenario then write a view spec for it. This allows you to keep the
high level behaviour in the features/scenarios and the lower level
details about the pages in view specs.

However, don't feel like you need to write a view spec for everything
on the page. If you have form with text fields and a button, and you
have a scenario that uses it, then don't feel like you have to write a
view spec for those. But if you need to go in and add a "cancel" link
 on the form and it's not doing anything special that requires a
scenario, write a view spec and ensure the cancel link exists (but
feel free to ignore the the things the scenario is already covering).

How does this all sound to you?

> On
> the users home page we discover the resources accessible by that user
> are listed.  From those resources the next layer of features become
> exposed, and so on.
> Is this getting closer to the mark or am I moving around the target but
> not quite getting it?

You're getting there. If anyone asks you are triangulating the target
so you can determine exactly where it lies. To a certain extent, we
all are. =)

Zach Dennis

More information about the rspec-users mailing list