Stories - Use view matchers rather than assigns[].should?

Hi there,

Just want to confirm I have this right. Writing a story,
assigns[:games].length.should == 30 fails for me complaining
assigns[:games]
is nil. It seems assigns isn’t set for story steps? I’ve changed this
to
response.should have_tag(".game", 30). Is this correct?

Tim.

On Wed, Apr 9, 2008 at 7:37 PM, Tim H. [email protected] wrote:

Hi there,

Just want to confirm I have this right. Writing a story,
assigns[:games].length.should == 30 fails for me complaining assigns[:games]
is nil. It seems assigns isn’t set for story steps? I’ve changed this to
response.should have_tag(".game", 30). Is this correct?

I would say that you shouldn’t be trying to test that sort of thing in
a story. The fact that Rails assigns stuff as instance variables in
views is a framework implementation detail, not externally visible
behavior.

Pat

On Apr 9, 2008, at 10:37 PM, “Tim H.” [email protected] wrote:

Hi there,

Just want to confirm I have this right. Writing a story, assigns
[:games].length.should == 30 fails for me complaining assigns
[:games] is nil. It seems assigns isn’t set for story steps? I’ve
changed this to response.should have_tag(".game", 30). Is this
correct?

Yep! The step has no access to intervals of the request.

Thanks Pat and David. I’m implementing paging (via will_paginate) and
thought I should start with a story. I think I grok what you’re saying
Pat

  • the stories should only be looking at “externally” visible stuff -
    i.e.
    what a real user can see or do… That’s why you consider
    controller.send(“current_user=”,…) a bit hacky right?

So to make sure I only have 30 records showing when there’s 40 in the db
I
should definitely be using have_tag…

Tim.

On 10.4.2008, at 6.20, Tim H. wrote:

Thanks Pat and David. I’m implementing paging (via will_paginate)
and thought I should start with a story. I think I grok what you’re
saying Pat - the stories should only be looking at “externally”
visible stuff - i.e. what a real user can see or do… That’s why
you consider controller.send(“current_user=”,…) a bit hacky right?

Yes. Just create a given that goes through the normal logging process.
You can parameterize it so that you can reuse it with different roles.

//jarkko


Jarkko L.
http://jlaine.net
http://dotherightthing.com
http://www.railsecommerce.com
http://odesign.fi

On Wed, Apr 9, 2008 at 8:20 PM, Tim H. [email protected]alid wrote:

Thanks Pat and David. I’m implementing paging (via will_paginate) and
thought I should start with a story. I think I grok what you’re saying Pat

  • the stories should only be looking at “externally” visible stuff - i.e.
    what a real user can see or do… That’s why you consider
    controller.send(“current_user=”,…) a bit hacky right?

I don’t actually think that that’s hacky. Let’s say you’ve got a
story that covers logging in. Does every single other story require
you to cover that same basic functionality? I don’t think so. The
tradeoff in this case is between purity and speed. Testing the exact
path the user takes is certainly more robust. otoh, how likely is the
authentication behavior going to fail? Not that likely. I think it’s
reasonable to skip that part, cutting down on the number of requests
that your stories make, in order to keep your story suite faster.

Pat

On 10 Apr 2008, at 04:20, Tim H. wrote:

Thanks Pat and David. I’m implementing paging (via will_paginate)
and thought I should start with a story. I think I grok what you’re
saying Pat - the stories should only be looking at “externally”
visible stuff - i.e. what a real user can see or do… That’s why
you consider controller.send(“current_user=”,…) a bit hacky right?

So to make sure I only have 30 records showing when there’s 40 in
the db I should definitely be using have_tag…

Tim.

Hi Tim

I’ve just done exactly this. In fact, the way it works out, your
view spec doesn’t have anything to do with how many items you have
displayed, that’s a controller/model issue with the call to
Model.paginate. In fact my view spec actually just had 3 model mocks
to render, while the controller spec checked the call to
Model.paginate(:per_page => 10) (is it :per_page?) and the story
checked that the correct number got displayed. The view was dumb,
just the way it should be.

And also I had a login step like Jarkko - in fact the first step of
every story was “Given a signed in admin user”.

Ashley


http://www.patchspace.co.uk/

On 10 Apr 2008, at 17:00, David C. wrote:

otooh - having some scenarios logging in using a post and some by
poking around under the hood creates an untested logical binding
between the post and the poking. This has the same risk associated
with it that raises so much concern about mocks without integration
tests that don’t use mocks.

I’m not saying that there should be a visible log-in step in every
scenario. I would just use a request (or series of requests) instead
of controller.send(“current_user=”,…).

Recently I’ve done a load of selenium-based stories and every single
one had to log in, except the one that checks you can’t do anything
when you are not logged in. There was no way round the login process,
so I had to put it in. But there were other stories that I couldn’t
do purely through the browser (eg those that needed users created and
attached to organisations) because not all of the required GUI had not
been built first*. For these I resorted to database access.

My questions are:

  • is this acceptable as a bootstrapping processes (direct DB creation
    of data until the GUI exists)

  • is this acceptable in the long run, if you write a story that shows
    that the database changes produce the corresponding user-visible
    changes?

Ashley

  • it was not an agile project


http://www.patchspace.co.uk/

On Thu, Apr 10, 2008 at 9:21 AM, Ashley M.
[email protected] wrote:

scenario. I would just use a request (or series of requests) instead
My questions are:

  • is this acceptable as a bootstrapping processes (direct DB creation
    of data until the GUI exists)

I think so. Keep in mind that not every step of every story needs to
be a round-trip request. It’s even good to write some stories that
don’t make requests at all!

In any test, you need to control the state of the word - the test
fixture. If your test requires a bit of bootstrapping in order to get
there, that’s fine. The only thing that matters is that your test
gives you confidence in the behavior you’re testing.

  • is this acceptable in the long run, if you write a story that shows
    that the database changes produce the corresponding user-visible
    changes?

I’m not entirely sure what you mean here. But generally if I’m
testing that the user sees something, then I also want to include the
step where they initiate that chain of events.

Pat

On Apr 10, 2008, at 11:20 AM, Pat M. wrote:

I don’t actually think that that’s hacky. Let’s say you’ve got a
story that covers logging in. Does every single other story require
you to cover that same basic functionality? I don’t think so. The
tradeoff in this case is between purity and speed. Testing the exact
path the user takes is certainly more robust. otoh, how likely is the
authentication behavior going to fail? Not that likely. I think it’s
reasonable to skip that part, cutting down on the number of requests
that your stories make, in order to keep your story suite faster.

otooh - having some scenarios logging in using a post and some by
poking around under the hood creates an untested logical binding
between the post and the poking. This has the same risk associated
with it that raises so much concern about mocks without integration
tests that don’t use mocks.

I’m not saying that there should be a visible log-in step in every
scenario. I would just use a request (or series of requests) instead
of controller.send(“current_user=”,…).

FWIW,
David

On Apr 10, 2008, at 12:48 PM, Pat M. wrote:

Keep in mind that not every step of every story needs to
be a round-trip request. It’s even good to write some stories that
don’t make requests at all!

I definitely agree with this, however I do see a difference between
accessing models directly through their API (which I do) and accessing
the internals of the request cycle (which I don’t).

In any test, you need to control the state of the world - the test
fixture. If your test requires a bit of bootstrapping in order to get
there, that’s fine. The only thing that matters is that your test
gives you confidence in the behavior you’re testing.

This is the ultimate bottom line. Tests are about confidence.

On Thu, Apr 10, 2008 at 2:57 PM, Ashley M.
[email protected] wrote:

Sorry wasn’t clear what I meant. I was thinking something like
Given …
When I run User.create!(:foo => “bar”)
Then the Users page should have a row with “bar” in the “foo” column

Gah, that looks hideous.

When I create a user with foo=“bar”

is better because it doesn’t expose the implementation. Just the
model concept and any relevant attributes.

If possible, I like to write it in a very narrative form:

Given a user named Pat
And the user is 22 years old
When I view the user list
Then I should see the user’s name and age

Your implementation of the steps can be at any level you want, for the
most part. But the stories should only be in business terms.

Pat

On 10 Apr 2008, at 23:06, Pat M. wrote:

Given …
When I run User.create!(:foo => “bar”)
Then the Users page should have a row with “bar” in the “foo”
column

Gah, that looks hideous.

I think you misunderstood the point - it’s supposed to look hideous :slight_smile:

What I meant was if you have a load of steps like

Given a user named Pat
And the user is 22 years old
When I view the user list
Then I should see the user’s name and age

But say that actually, “Given a user named Pat” and “Given the user
is 22 years old” are implemented as DB API calls - in this case is
there merit to having a special set of stories on one side, just to
verify that your low-level steps actually produce the user-facing data
you expect, as if they used the GUI to create the data?

I sometimes write “assumption” specs for third party code, if I am
relying on behaviour I’m unsure about, just so if the lib API changes
it gets flagged. I saw this as an extension of the idea, not a
suggestion to send ActiveRecord method calls to a client’s marketing
director!!! (I’m sure there’s some bizarre political situation
somewhere where that might have an advantage though…)

Ashley


http://www.patchspace.co.uk/

On 10 Apr 2008, at 17:59, David C. wrote:

I definitely agree with this, however I do see a difference between
accessing models directly through their API (which I do) and accessing
the internals of the request cycle (which I don’t).

Ok that’s what I was doing - not interfering with anything, just using
a lower-level API in the same story as a high-level API. Perhaps it
wouldn’t have felt as strange if I was using a web service request
instead of ORM calls?

and Pat wrote:

  • is this acceptable in the long run, if you write a story that shows
    that the database changes produce the corresponding user-visible
    changes?

I’m not entirely sure what you mean here. But generally if I’m
testing that the user sees something, then I also want to include the
step where they initiate that chain of events.

Sorry wasn’t clear what I meant. I was thinking something like
Given …
When I run User.create!(:foo => “bar”)
Then the Users page should have a row with “bar” in the “foo” column

etc…

Ashley


http://www.patchspace.co.uk/

On 10 Apr 2008, at 23:38, Pat M. wrote:

I don’t know what you mean by a special set of stories. In the
example I gave, the Given steps would most likely be implemented as AR
calls - not as separate requests. The When and Then would likely be
implemented as an HTTP request and an assertion on the returned HTML.
But there’s no way to tell that from the story narrative.

This is the key to me. Ultimately there’s no way to prove that the
story does anything until someone sees it run - at least on a real
browser. Arguably even webrat etc don’t demonstrably prove that the
app works. That was my feeling with using DB calls, they aren’t
demonstrable enough.

I had a handover meeting with my client today, and for the
functionality I built he was most interested in seeing the stories,
first in text and then actually run. And actually it was satisfying
for me to run them, knowing there’s no disputing something you can see
running in front of your eyes. But I felt the need to apologise for
steps that “cheated”, such as those that inspected the database for
model states, instead of pages for content keywords.

And
sometimes if the logic is complex and will take a couple iterations, I
might first implement the When and Then steps as AR calls, and then as
we build up the HTML pages around that infrastructure, I’d convert the
step implementations to go through the web request.

Are we somewhat getting on the same page by now? :slight_smile:

Uhuh :smiley: That’s what I meant by “bootstrapping” - writing DB API
steps to get yourself going. Then you have two choices - “upgrade”
them to “real” steps like you say above, or write “characterization
tests” like you say below.

I was just wondering what people thought of the two opinions.

Sorry for taking so long to get my point across… typing posts at
100mph in between coding, and expecting everyone to read my mind…

Michael Feathers, in Working Effectively with Legacy Code, calls these
characterization tests. They can certainly be very useful.

Thanks for the book recommendation, I’ve forwarded it to some people I
know that haven’t had the luxury of using Ruby full time.

Ashley


http://www.patchspace.co.uk/

On Thu, Apr 10, 2008 at 6:38 PM, Pat M. [email protected] wrote:

On Thu, Apr 10, 2008 at 3:30 PM, Ashley M.

But there’s no way to tell that from the story narrative. And
sometimes if the logic is complex and will take a couple iterations, I
might first implement the When and Then steps as AR calls, and then as
we build up the HTML pages around that infrastructure, I’d convert the
step implementations to go through the web request.

I’m working on a project right now in which the business rules and
logic took some time to discover via iteration and experimentation.
The UI work started later and overlapped somewhat.

I started by writing a plain text story, and steps which worked at the
AR level. I’ve done the UI work mostly with specs and not stories.

I’m now at the point of converting the steps into the equivalent of a
‘traditional’ Rails integration test.

BUT

I’m thinking that I might just write a whole new xxx_steps.rb file
which would run the same story but at the real user interaction level,
and keep the model level steps also. I still haven’t convinced myself
one way or the other.


Rick DeNatale

My blog on Ruby
http://talklikeaduck.denhaven2.com/

On Thu, Apr 10, 2008 at 3:30 PM, Ashley M.
[email protected] wrote:

I think you misunderstood the point - it’s supposed to look hideous :slight_smile:

Yes, I am thoroughly confused.

there merit to having a special set of stories on one side, just to
verify that your low-level steps actually produce the user-facing data
you expect, as if they used the GUI to create the data?

I don’t know what you mean by a special set of stories. In the
example I gave, the Given steps would most likely be implemented as AR
calls - not as separate requests. The When and Then would likely be
implemented as an HTTP request and an assertion on the returned HTML.
But there’s no way to tell that from the story narrative. And
sometimes if the logic is complex and will take a couple iterations, I
might first implement the When and Then steps as AR calls, and then as
we build up the HTML pages around that infrastructure, I’d convert the
step implementations to go through the web request.

Are we somewhat getting on the same page by now? :slight_smile:

I sometimes write “assumption” specs for third party code, if I am
relying on behaviour I’m unsure about, just so if the lib API changes
it gets flagged. I saw this as an extension of the idea, not a
suggestion to send ActiveRecord method calls to a client’s marketing
director!!! (I’m sure there’s some bizarre political situation
somewhere where that might have an advantage though…)

Michael Feathers, in Working Effectively with Legacy Code, calls these
characterization tests. They can certainly be very useful.

Pat

I read about webrat and stories 30 mins ago -
http://www.benmabey.com/2008/02/04/rspec-plain-text-stories-webrat-chunky-bacon/-
good article.

Tim.

When I create a user with foo=“bar”

is better because it doesn’t expose the implementation. Just the
model concept and any relevant attributes.

I hide model details from Stories by using webrat and form field labels.

When I create a user with Username: kamal, Password: test
And click submit

Seems safer that way as the views get tested at the same time.

Regards,
kamal

On Apr 11, 2008, at 4:44 AM, Ashley M.
[email protected] wrote:

Wow, I had never thought of this. Could you really write a story that
could be executed in two different environments based on the steps
file that got loaded?

Absolutely. That is, in fact, one benefit of plain text stories that
we don’t have with ruby stories … Yet.

This forum is not affiliated to the Ruby language, Ruby on Rails framework, nor any Ruby applications discussed here.

| Privacy Policy | Terms of Service | Remote Ruby Jobs