Poor Men Story Runner
By Renzo Borgatti on October 30th, 2008
Tagged with: rspec, rails, storyrunner
Say that for some reasons like for example time constraints on the project, lack of customer collaboration or lack of business analysts you can’t maintain a full fledged automated story base. In that case one option could be to maintain the story runner format to describe the feature to implement but not try to make that executable. I know, I know, what a waste for such a great opportunity. But I’m talking about a desperate case.
As funky as it sounds, you can try to implement the plain text story in rspec as controller specs with integrated view. For example:
1 describe BlogsController, "blog details page" do
2 integrate_views
3
4 before(:each) do
5 Given "the user is logged in"
6 When "I click on a blog post"
7 end
8
9 it { Then "the blog detail view is displayed" }
10 it { And "the full text of the blog is shown" }
11 it { And "the comment list section is shown" }
12
13 end
14
15 [:Given, :When, :Then, :And].each do |method_name|
16 self.class.send :define_method, method_name do |what|
17 self.send(what.gsub(' ','_'))
18 end
19 endYes, very very not-readable. It just destroy all the effort to create stories in plain text. But it’s something a developer can read. The next step is to create a method for each of the descriptive texts, replacing blanks with underscores:
1 def the_user_is_logged_in
2 @user = login
3 end
4
5 def I_click_on_a_blog_post
6 @blog = stub_model(Blog,
7 :title => "Random thoughts.",
8 :comments => comments,
9 :text => "MIDWAY upon the journey of our life")
10 Blog.should_receive(:find_by_id).with(1).and_return(@blog)
11 get :show, :id => 1
12 end
13
14 def the_blog_detail_view_is_displayed
15 response.should have_tag("div#blog") do
16 with_tag("strong", @blog.title)
17 end
18 end
19
20 def the_full_text_of_the_blog_is_shown
21 response.should have_tag("div#blog") do
22 with_tag("div#text", @blog.text)
23 end
24 end
25
26 def the_comment_list_section_is_shown
27 response.should have_tag("div#blog") do
28 with_tag("div#comments") do
29 with_tag("div#comment", 5)
30 end
31 end
32 end
As you probably guessed already, this is the first scenario for a blog section on some web page. You can click on the “more” link to read more and access comments to the blog post. The plan is to implement the other scenarios in the same spec file changing the describe block to change the target controller. The specs are just scratching the surface of the view, then you’ll need to change spec to implement other part of the system.
Another interesting thing is that for this to be called “integration” test, I shouldn’t have used any stub_model instruction. Correct. First step I want to create it fast, no database thinking. Second step I’ll remove all stubs and using some way of talking to the database (FixtureReplacement for example) I’ll be using real connections to the model and therefore to the database. At the end, a kind of acceptance testing.
I know what you’d like to ask now: is this really any better than just plain run the Story Runner itself? Not at all. It’s absolutely a bad practice to use RSpec like this, I don’t want to suggest in any way that this can substitute the story runner. But in case of emergency (read, fixed scope, fixed price, fixed time projects) where the customer is not helping writing stories, where there are no business analysts and everything should be done by developers, dropping the story runner is probably the less of all possible pains. You should also consider that if you are using Watir or Selenium on Rails connected to the story runner, the effort of maintaining such an environment sensible acceptance framework is big.
Specifically:
- You don’t need the infrastructure to run stories which is usually a separated task from running specs
- You don’t need to maintain steps either
- You don’t need to attach the story runner binary to the continuous integration, stories will run as normal specs.
- You are free to maintain story texts outside the project, on a wiki or online somewhere.
- Coverage with rcov is just part of the package. For stories you can’t know how well are you covering that given aspect of the application. At least, I thought about it and I don’t know how to deal with the problem.
Well, hope you can forgive me for this post but find the idea useful for your project.

Comments