Thursday, April 16, 2009

A Quicky Scenario

‹prev | My Chain | next›

Up next in my chain is the search for a keyword in the recipe summary. The scenario:
cstrom@jaynestown:~/repos/eee-code$ cucumber features/recipe_search.feature \
-n -s "Matching a word in the recipe summary"
Feature: Search for recipes

So that I can find one recipe among many
As a web user
I want to be able search recipes
Scenario: Matching a word in the recipe summary
Given a "pancake" recipe with a "Yummy!" summary
And a "french toast" recipe with a "Delicious" summary
When I search for "yummy"
Then I should see the "pancake" recipe in the search results
And I should not see the "french toast" recipe in the search results


1 scenario
2 steps skipped
3 steps pending (3 with no step definition)

You can use these snippets to implement pending steps which have no step definition:

Given /^a "pancake" recipe with a "Yummy!" summary$/ do
end

Given /^a "french toast" recipe with a "Delicious" summary$/ do
end

When /^I search for "yummy"$/ do
end
The two Then steps (for the "pancake" and "french toast" recipes) look very similar. I implement the "pancake" one first, then generalize it to work with with both:
Given /^a "(.+)" recipe with a "(.+)" summary$/ do |title, keyword|
date = Date.new(2009, 4, 12)
permalink = "id-#{title.gsub(/\W/, '-')}"

recipe = {
:title => title,
:date => date,
:summary => "This is #{keyword}"
}

RestClient.put "#{@@db}/#{permalink}",
recipe.to_json,
:content_type => 'application/json'
end
The next Given step, the 1 second wait, is already complete.

The When step looks suspiciously like the When step from last night's work (When I search for "chocolate"). To make that step definition work for both, it can be quickly reworked as:
When /^I search for "(.+)"$/ do |keyword|
visit("/recipes/search?q=#{keyword}")
end
I get the first Then step for free thanks to my violation of YAGNI yesterday. Luckily I did need it this time!

Last up for this scenario is specifying that the search results should not include the french toast recipe (because it does not have the word "yummy" in it). I implement this step similarly to the should have step:
Then /^I should not see the "(.+)" recipe in the search results$/ do |title|
response.should_not have_selector("a", :content => title)
end
This is slightly less specific than the positive match (not matching the href). When matching things, you should do everything possible to find the right element—be as specific as possible. When verifying the absence of something, you should also do everything possible to verify that it is not there—by being a little less specific.

That does it. An entire scenario finished without adding any code, which means that couchdb-lucene indexing code from the other night implements these steps. The lack of unit tests covering that indexing code makes these scenario steps that much more important for verification of the functionality.
(commit)

No comments:

Post a Comment