Story Runner - constructive criticism 15 Oct 2007
If you keep up with RSpec development you’ll know that RBehave has been integrated into RSpec and is known as the “Story” Runner. This is a unfolding of current thoughts and criticism, I apologize for any lack of explanation, but I need to do a quick braindump.

I love the concept of Story Runner, but I do not like it’s current syntax. Below are the criticism’s for why. First though the code example I’ll use to discuss the Story syntax.

Story "View Home Page", %{
  As a user I want to view my home page
  So that I can get a birds eye view of the system
}, :type => RailsStory do

  Scenario "Latest published article" do
    Given "an author named", "Zach" do |name|
       @user = User.create! :name => name

    When "he visits the home page", "/" do |path|
       get path

    Then "he should see the latest article published front and center" do
       # ... do something to see the article shows as expeted


Story Description

The story description is hideous. It requires a description, and then the story description, and then a type flag (at least for Rails projects). The Story itself should contain it’s actual story description. The pseudo description set in the first parameter and the :type flag should be able to be dropped. Right now these two things do not add value, but decrease customer readability.

Story Do/End Blocks

Everything is organized with do/end blocks. While I love the closure capabilities of ruby I am not a big fan of overusing blocks in Story files themselves. I would much rather drop the do/end blocks unless they provide needed clarity.

I’d like to remove the do/end block on Story because it the definition of the file format should read.. “All Scenarios belong to the preceding Story declaration”. Which to me is still just as readable.

Scenario Do/End Blocks

These should stay put. To me these are essential for providing clarity amongst your acceptance tests which scenario they are pertaining to.

Story Part Do/End Blocks

Story part (Given, When, Then, And) do/end blocks need to go away completely. They allow for developers to embed code directly into the high level story, which immediately reduces the readability from both a customer and developer perspective.

It has been mentioned that you can use editors code folding techniques to hide the code, but as pointed out on the rspec mailing list I don’t want my customer to have to use a code editor to read the acceptance tests.

Argument Passing

After every story part in the above example you have the ability to pass in arguments to the do/end block. When this adds value it makes sense to do this, but when it is a trivial piece of information it doesn’t seem to add any value. Instead it detracts readability.

It detracts readability by creating new tokens a customer has to visually parse, both in the argument list for the story part and also the argument list for the do/end block. It also makes data that may not be important seem important because they are singled out as their own arguments.

Argument passing should be used to add value to the story part with something that helps identify a behavior that is going to happen that your test is going to depend on. Usually this is not the user’s name or the root path (”/”) of a site, although in some cases it may be.

The Process Is Flawed

The ideal process is having a customer write and own the stories and the acceptance tests. As these change the customer should be responsible for updating them. The developers should be responsible for implementing them.

Given the above format once you add embedded code to a Story part you immediately reduce the readability from a customer’s perspective to own and maintain that Story and it’s acceptance tests should it change in the future. Also if a customer changes a Story should he/she be responsible for deleting the developers implementation of last acceptance test?

So the process is flawed. We shouldn’t have a format which doesn’t provide consistency to both the developer and the customer. So we need to tweak the Story format to enable a format which is consistent at both creation and change/update time of a Story and/or it’s acceptance tests.

Reusable Code

Embedding code inside a Story part renders it non-reusable. So to combat this you create a helper method and call from within the Story part’s do/end block. So now you have a nice clean description and with a do/end block wrapping a helper method, like below:

Given "a user logged into the system", "Joe" do |name|
  @user = User.create! name
  login_as @user

I see this and I want to refactor this. Clearly the description well named. I should be able to rely on a similarly well named helper method to handle creating or finding a user and logging that user in. If I do this then why do I need a do/end block (besides the fact of RSpec using it to trigger a pending Story)?

It seems so far that you don’t need a do/end block. It doesn’t add value. It takes away value.

blog comments powered by Disqus