Guest post by Alister Scott
I’ve recently been putting some amount of thought into how to write good Cucumber features. One the reasons I love Cucumber so much is its language focus; meaning it makes you think about things like sentence function more than other testing frameworks I have used. One element of sentence function usage in Cucumber that’s important is whether you should write imperative (communicative) or declarative (informative) sentences for your steps. I’ll provide a couple of examples to show the differences.
An imperative (communicative) Cucumber scenario
Scenario: Submit the form with correct data (imperative) Given I am on the watir example form When I set "What is your name?" to "Alister" And I set "What is your story?" to "I like ruby" And I set "What testing tool do you like?" to "Watir" And I click "Submit" Then I should see the message "Thanks! Your response has been recorded."
Each step is a command, or instruction, so it’s pretty clear what is being done.
A declarative (informative) Cucumber scenario
Scenario: Submit the form with correct data (declarative) Given I am on the watir example form When I submit the form with correct data Then I should see the correct message
Each step states an idea, so sometimes it’s not really clear precisely what is being done.
Imperative vs Declarative
There’s some quite good articles about writing Cucumber features/scenarios around. One such article that stood out to me was written in May 2008 about RSpec Story Runner, and whether you should use an imperative or declarative style. The answer is, of course, it depends, but most people tend to lean towards the declarative style, just the way that a lot of programmers prefer declarative programming. I am actually swinging towards imperative style cucumber features and steps; the reasons for which I will explain below.
Running Imperative Features gives you richer output
With the two examples above, I have kinda cheated, in that the step definitions for the declarative style calls imperative steps. For example, this is the declarative step defintion:
When /^I submit the form with correct data$/ do When "I set \"What is your name?\" to \"Alister\"" And "I set \"What is your story?\" to \"I like ruby\"" And "I set \"What testing tool do you like?\" to \"Watir\"" And "I click \"Submit\"" end
This is all well and good, as you can now have multiple cucumber steps that call the same thing, it’s DRYish, but the problem is when you run the step “When I submit the form with correct data”, that’s all you get.
Compare this to the imperative step results, which whilst calling exactly the same code, give you a lot more richness.
Writing imperative scenarios allow you to utilise things advanced cucumber functionality
Two table based Cucumber features I like using are scenario outlines, and multiline step arguments, but these don’t make a lot of sense if you’re using a declarative style. For example, the imperative scenario could be easily adapted to use a scenario outline, whereas the declarative style would mean writing more declarative steps.
Scenario Outline: Submit the form with correct data (imperative - outline) Given I am on the watir example form When I set "What is your name?" to "" And I set "What is your story?" to "" And I set "What testing tool do you like?" to "" And I click "Submit" Then I should see the message "Thanks! Your response has been recorded."
Examples: | name | story | tool | | Alister | I Like ruby | Watir | | Mozart | I like java | Selenium |
Writing declarative scenarios often means hidden detail
As you move to more and more declarative scenarios, more and more details become hidden in cucumber step definitions and library code. As Rasmus pointed out on Jared Quinert’s blog on does Cucumber suck:
...tests end up looking like the one test to rule them all™: Given everything is set up When I submit correct data Then everything should be OK
To wrap up, I’m not saying don’t go declarative, what I am saying is that you lose certain things in Cucumber when you do, but whether this is a big deal or not depends on what you’re trying to get out of it. In the meantime, I’ll continue to experiment and see what works and what doesn’t.