Cucumber Scenarios – Redux

Back when I was a BDD n00b I had dwelled into different styles of writing Cucumber Scenarios here. After six to seven months of usage and reading The Cucumber Book by Matt Wayne, things are lot more clear than what it was then.

In this post I want to bust some misconceptions about Cucumber and shed some light into the way it needs to be used.

What is Cucumber?

First let us understand what Cucumber really stands for in the BDD eco-system. The book definition is like this –

Cucumber is a tool that facilitates discovery and use of a ubiquitous language within a team.

This understanding of Cucumber is critical before we jump into writing Cucumber Scenarios. It’s a tool for unearthing language of the domain and there by facilitating an understanding of the domain.

It’s primary focus is not an Integration Test Tool or worst an Unit Test Tool. In the end of it if it can help in catching Regression issues that is the happy side effect of using Cucumber.

Since the idea of Cucumber is to find the ubiquitous language of the domain, the Cucumber scenarios need to be worded carefully so that it makes lot of sense to the technical and functional teams. Cramming lot of technical details (like UI details) is not a great idea while coming up with scenarios. Cucumber scenarios goes on to become the living documentation of the system.

Declarative or Imperative?

Imperative Style

Scenario: Open Account
Given I am in new account page
When I fill in Name with "Arun"
And I fill in DoB with "25/1/89"
And I select "Male" from "Sex"
And I press "Submit"
Then I should see "Account created."

Declarative Style

Scenario: Open Account
Given I do not have an account
When I sign up for an account
Then my account has to be created

As evident from the two scenarios, imperative one is tied up to the UI implementation of the system. It doesn’t really reveal the intent of the scenario properly. The declarative one on the other hand is really working at
an abstract level and probably communicates well to both functional and technical people. The declarative style clearly reveals the intent more succintly to the reader.

Other problems inherent with imperative style is maintenance, a slight change in UI like change of button caption will lead to change in the Scenario definition itself, which seems not right because your domain hasn’t changed to ensue a change in the Ubiquitous language of the domain.

Outside-In Development

Early days of BDD I was under the misconception that outside-in development means we have to drive out our design from UI, then drill down to controller and models. That was just a stupid understanding from my
side. Later I realized it was just meant to say Outside of what we want to discover. So it is perfectly fine to use Cucumber first to build the Domain Model layer of the system and later build UI on top of it.

Courtesy : The Cucumber Book

As shown in the figure (courtesy: The Cucumber Book) above, it is perfectly valid and sensible to run your Cukes on top of the domain model and then switch to full blown integrated system. So in the first few days, probably you will be driving out the design on Domain Layer from Cucumber and once it is done you can step into building the UI on top of it.

The switch from Domain to UI would entail a change Cucumber support code to point to UI (through Capybara) to make the Scenarios pass.

The point to realize is that when you move from Domain Model to UI Layer the language of your scenarios are not changing it remains same.

Pitfalls & Myths

Cucumber is hard to maintain

Yes they can be extremely hard to maintain if you go by the imperative route. A small label change in UI will break scenarios. Lately I had met many Ruby developers in Agile Conf & Ruby Conf India, and the common rant against Cucumber was it was hard to maintain.

I am really not sure if you do Cucumber in Declarative Style will it lead to maintenance problems or not? Declarative style reveals us the understanding of the domain. Now if the domain itself changes, then your code has to change, your tests have to change and so your Cucumber Scenario has to change. I cannot quite clearly see how maintenance problem creep in if Cucumber is used the proper way it is meant to be.

Writing Imperative Style

If you intend to write Imperative style cucumber scenario then the best place to do that will be RSpec Integration Tests and not in Cucumber.

Picture this

When I fill in "Name" with "Arun"
When I press "Submit"

can also written in same readable way in RSpec as

fill_in :name, :with => "Arun"
click_button "Submit"

And other places where imperative style creeps in is

And I press "Submit"
Then I should be on account page
And I should see "Arun"
And I should see "25/01/1989"
And I should see "Male"

Here we are testing UI elements using elaborate Cucumber Scenarios. Probably the best place for this code to live is RSpec View Tests.

Such test add overhead to maintenance and do not promote any readability for the stakeholders. Worst it doesn’t help in arriving at the ubiquitous language of the domain.

Pushing Unit Tests to Cucumber

This the case of overusing Cucumber without relying on Unit Tests. Consider the Scenarios below

Scenario: Create Account
Scenario: Create Account without Name
Scenario: Create Account without DoB
Scenario: Create Account without Name & DoB

Probably difference in these Scenarios may be the flash message which gets displayed. There is no need for all such trivial variations sitting in Cucumber, instead the last 3 scenarios can be pushed to the RSpec Model or even Controller layer and Cucumber can be left with Create Account scenario in Declarative style alone.

Remember writing Cucumber is not an excuse for not writing RSpecs. Cucumber creators themselves heavily advocate to use Unit Tests when we drill down from failing cukes to domain layer.

Bloated Step Definitions

The Step Definition file needs to be maintained cleanly without cramming in lot of code into that. Each step definition should delegate to the Cucumber support layer through a neat DSL. One of the good things if you follow this strictly is that at the end of cycle you will be able to arrive at a clean DSL for your domain.

For example

Given /^When I sign up for an account$/ do
  sign_up :name => "arun", :dob => "25/01/1989"
end

As you can see in Step Definition it just call for a sign_up method, here we are not putting Capybara Steps or Model interaction code directly.

sign_up method can live independently in support layer inside a module like AccountDSL.

module AccountDSL
  def sign_up(params)
     visit new_account_path
     fill_in :name, :with => params[:name]
     fill_in :dob, :with => params[:dob]
     click_button "submit"
   end
end

So the UI interactions are localized into the single method. And the Step Definition can be reused any where within multiple scenarios. Even if a UI redesign happen you need to bother only about changing AccountDSL::sign_up method.

Also before we got into the UI building, we might have worked with same scenario interacting directly with Domain Layer. At that point probably the sign_up method would have read like this

module AccountDSL
   def sign_up(params)
     Account.sign_up(params)
   end
end

Once the UI is ready it is just the question of swapping the implementation of sign_up method.

Summary

As they say Sign of well-written specs: the –format documentation gives a nice summary of all the project features to any stakeholder (link).

Sign of well-written Cucumber Scenario is to promote understanding of the domain and to derive an unbiquitous language of the domain.

Tidying up your RSpecs – 1

This is a cross post from our company blog.

Almost everyone in Ruby world agrees that RSpecs are a great way to test code in both Ruby and Rails projects.

Today, I want to share some of the tips which I had learnt and used in my RSpecs which has really help to tidy up the RSpec code and output.

Explicit Subjects & Contexts

Consider a RSpec for a Rails Controller. Assume that controller actions require a user to authenticate himself before performing any of the actions. In order to test this aspect we can write RSpec like this

describe PlacesController do
  describe "access control" do
    describe "for non-signed in users" do
      it "should redirect to sign in page for delete :destroy" do
        delete :destroy, :id => "1234"
        response.should redirect_to(new_user_session_path)
      end
      it "should redirect to sign in page for get :index" do
        get :index
        response.should redirect_to(new_user_session_path)
      end
      it "should redirect to sign in page for get :show" do
        get :show, :id => "123"
        response.should redirect_to(new_user_session_path)
      end
    end
  end

The above specs can be repeated for each and every action in the controller. Now when I run the above spec the output will look something like this.

for non-signed in users
  should redirect to sign in page for delete :destroy
  should redirect to sign in page for get :index
  should redirect to sign in page for get :show

The output doesn’t read really that great. One of the good guideline which I believe for writing good RSpec is that the output should be really readable like a prose and easily convey the behavior or intent of the code it tests. So it’s time to tweak the code and make the output more readable. Also if you look the code has lot of repeatition of response.should redirect_to all over the place. So let us clean up that with explicit subject and context.

describe PlacesController do
  describe "access control" do
    context "for non-signed in users" do

      subject { response }

      context "delete :destroy" do
        before { delete :destroy, :id => "1234" }
        it { should redirect_to(new_user_session_path) }
      end

      context "get :index" do
        before { get :index }
        it { should redirect_to(new_user_session_path) }
      end

      context "get :show" do
        before { get :show, :id => "123" }
        it { should redirect_to(new_user_session_path) }
      end
    end
  end
end

Notice how I have used the subject {} to specify an explicit subject. The implicit subject for any RSpec is the class which is used with the describe at top. In the above case it would be PlacesController. By specifying an explicit subject we are declaring the object which need to evaluated for subsequent tests. In this case it has been set to the response object. The usage of context really makes the code much clean and readable. Basically it sets the context for each test case while running. Now if we run the RSpec the output looks much cleaner like this.


for non-signed in users
  delete :destroy
    should redirect to "/users/sign_in"
  get :index
    should redirect to "/users/sign_in"
  get :show
    should redirect to "/users/sign_in"

Here is another example of an explicit subject below. This is an RSpec for User Role assignments with CanCan.


describe Ability do
  context "Admin Role" do
    before(:each) do
      @admin = Factory(:admin)
      @ability = Ability.new(@admin)
    end

    subject { @ability }
    it { should be_able_to(:manage,User) }
    it { should be_able_to(:manage, Restuarant)}
    it { should be_able_to(:manage,Place) }
  end
end

The code really is looking succinct and clean with the usage of subject {} . Without the subject it would have been a drudgery to write the same piece with describe…it..end blocks.

Shared Examples

Now let us turn our attention to the technique of Shared Examples which keeps our RSpec code DRY. Here is an example which tests the Links appearing in a footer of the page based on the User Role.

shared_examples "footer" do |links|
  links.each do |link|
    it "with #{link}" do
      within("div#footer") do
        page.should have_xpath("//nav/ul/li/a[contains(text(),'#{link}')]")
      end
    end
  end
end

describe "Footer" do
  extend LinkHelpers

   context "not signed in user" do
    before { visit search_home_path }
    it_behaves_like "a footer", normal_links
   end

   context "Admin" do
     before(:each) do
      @admin = Factory(:admin)
      sign_in_user(@admin.email,"password")
     end
     it_behaves_like "a footer", admin_links
   end
end

The code is pretty self-explanatory. For a noumal user I want a bunch of links to appear in the footer. For an admin user I want another set of links to appear. In the code above normal_links method gives the array of links for normal user and admin_links gives the array of links for admin user. [Note normal_links and admin_links are methods defined in a module LinkHelpers which I am extending below describe]

Coming to the DRY part. The code for doing the actual testing is put under a shared_example “footer” and it is invoked with it_behaves_like call. Also note we can pass zero or any number of arguments to shared_example. In the example above it accepts a single argument of Array type.

Let us see the output of the above code:

Footer
   not signed in user
     behaves like a footer
       with About Us
       with Feedback
       with Disclaimer
   Admin
     behaves like a footer
       with About Us
       with Feedback
       with Disclaimer
       with Manage Restaurant
       with Manage Place

Even though the behavior and output is correct, the above results and code doesn’t read proper. Probably we shouldn’t call display of footer as a behavior. RSpec to rescue again! We can customize what appears in the output (in this case “behaves like a”) as well as rename the function it_behaves_like to something which is more appropriate for the context.

So for diplay of a footer it may be good to have a function like it_has_a “footer” instead of it_behaves_like “a footer”. Now let us see how this done:

RSpec.configure do |c|
   c.alias_it_should_behave_like_to :it_has_a, 'has a'
end

shared_examples "footer" do |links|
   links.each do |link|
     it "with #{link}" do
       within("div#footer") do
         page.should have_xpath("//nav/ul/li/a[contains(text(),'#{link}')]")
       end
     end
   end
end

describe "Footer" do
   extend LinkHelpers

   context "not signed in user" do
     before { visit search_home_path }
     it_has_a "footer", normal_links
   end

   context "Admin" do
     before(:each) do
       @admin = Factory(:admin)
       sign_in_user(@admin.email,"password")
     end
     it_has_a "footer", admin_links
  end
end

In the above code RSpec.configure block actually aliases the it_behaves_like function it_has_a and specifies that “has a” should be the output instead of “behavies like a” while the specs are run. Let us check the output now:


Footer
   not signed in user
     has a footer
       with About Us
       with Feedback
       with Disclaimer
   Admin
     has a footer
       with About Us
       with Feedback
       with Disclaimer
       with Manage Restaurant
       with Manage Place

To Conclude

  • Use context with describe and make the test more readable instead of just getting stuck with describe..describe…it kind of format.
  • Give a before {} block for any context to set any pre-conditions before running the context.
  • Wherever possible declare an explicit subject and reduce the cruft in the specs.
  • DRY up your RSpec with shared_examples.
  • Customize the method name and output by aliasing in RSpec.configure.

Hope this post was helpful, do share your thoughts if any!