Apr 26, 2009

Some Progress On My BDD Blog Project

I finally got around to doing some more work on my BDD Blog project over the weekend. Up to this point I had mostly been just experimenting (here, here and here), but this time I decided I was going to try and write and implement a real scenario.

My goal though is not so much to implement code. Instead I'm still trying to learn how to write features and specs. I want to get to the point where I'm comfortable enough with Cucumber, Webrat and RSpec that I'm confident I can express all the features for a release without wasting my time.

So lets start with the feature I'm going to try and implement. The feature it self is very straight forward. It walks through the process used by an author when creating a new post.

Scenario: save a draft post
Given I am logged in as John Doe
And I am on the post creation page
And I have filled in the title with "Get Rich Overnight"
And I have filled in the body with "lorem ipsum"
When I click the "Create" button
Then I should be on the post index page
And I should see "Post successfully created"
And I should see "1 to 1 of 1 posts"
And there should only be 1 post listed
And the first post's title should be "Get Rich Overnight"
And the first post's author should be "John Doe"
And the first post's status should be "draft"

I've already played around with AuthLogic and demonstrated it's use but there's a minor change here. I'm no longer testing authentication so I needed to reduce the login process to a single given statement.
Given I am logged in as John Doe

The code I used to do that is pretty straight foward.
Given /^I am logged in as (.+)$/ do |login|
Given "I am the registered user #{login}"
visit path_to("the login page")
fill_in('Login', :with => login)
fill_in('Password', :with => "password")
click_button("Login")
end

The only thing even remotely interesting here is that I'm calling one of my previously defined 'Given' statements from within this one.

The next few statements are very straight forward and were implemented entirely in cucumber with the existing scaffold for the Post resource.
And I am on the post creation page
And I have filled in the title with "Get Rich Overnight"
And I have filled in the body with "lorem ipsum"
When I click the "Create" button
Then I should be on the post index page
And I should see "Post successfully created"
The next line in this scenario:
And I should see "1 to 1 of 1 posts"
I now realize didn't belong in this scenario (I'll refactor that out later) but since I learned something while implementing it I'm going to share.

Specifically, what I learned was this statement has no real purpose. I wanted to make sure that only the new post was present but all this really does it check to see if the "1 to 1 of 1 posts" text is present. It doesn't provide any real validation of the number of posts on the page. In the future I'll move this out to a new feature that's specifically written to test the pagination summary.

This line was not originally in my feature:
And there should only be 1 post listed
I added it when I realized my mistake with the previous line. This statement directly tests the number of posts on the page by counting the table rows in the post index table. It's implementation is very straight forward:
Then /^there should only be (\d+) posts? listed$/ do |count|
response.should have_tag("tr" , :count =>(count.to_i + 1))
end

The next three lines:
And the first post's title should be "Get Rich Overnight"
And the first post's author should be "John Doe"
And the first post's status should be "draft"

These lines were all very similar. They are simply looking to make sure that the contents of specific columns in the post index table have the correct information. This statement is implemented with the following code:
Then /^the (.+) post's (.+) should be "([^\"]*)"$/ do |index, column, text|
response.should have_selector("table>tr:nth-child(#{position_to(index) + 1})") do |tr|
tr.should have_selector("td[class=
'#{column}']") do |td|
td.should contain(text)
end
end
end
There's not much special there but it was my first attempt at really trying to use the CSS selector notation. Maybe after I'm more comfortable with it I'll devote a post to just that but for now I'll just explain this method.

In a nutshell it simply looks to make sure that nth row in the post index table has a td tag with a class matching the column name and that it's content matches the text passed in.

You may also notice I have a poorly named method called position_to in this method that simply turns the english words; first, second, third, etc... into the appropriate fixnum. Hopefully down the road I can find a library that does this but if not maybe I'll expand my approach into a full fledged gem.

This pretty much covered what I did with Cucumber and Webrat to fully implement this scenario but I did dip down into some view, controller and model specs to get the job done. I'll save that for another post.

No comments: