Getting Started with Padrino and BDD

Padrino is a web framework, closely related to its cousin, the Sinatra web framework. It tries to offer the flexibility of development of Sinatra and a wide array of helpers, tools and add-ons of Rails.

Padrino, Italian for “godfather”, is built on top of Sinatra, so you can use all your knowledge gained from the previous Sinatra series published on this site. However, it is somewhat different, as it provides some conventions that look very similar to the ones found in the previously mentioned articles, as you will see. By the way, I will use Ruby 1.9.2 for this tutorial.

To make it easier, I’ll manage it via RVM. The steps to set up RVM, if you haven’t already, are outlined in this article by Glenn Goodrich of Rubysource fame. Once you have RVM and Ruby 1.9.2 installed, make a gemset for this application. I am calling mine “rubysource”, as you can see below:

$ rvm use 1.9.2@rubysource --create

Install Padrino

--ADVERTISEMENT--

To install Padrino:

$ gem install padrino

Once done, create a new project by running:

$ padrino g project rubytoday -t cucumber -b

g is short form for generate

-t is a switch used to specify a testing framework, in this case
I’ve specified Cucumber, this also includes RSpec

-b tells Padrino to use Bundler for managing the gems

This creates a project named rubytoday.

Once you change to the rubytoday directory, if you’ve used Rails, you’ll see a somewhat similar directory structure to a Rails project:

Now that we have the initial bare app, it’s a good time to check it into Git. That way, you can revert to this state again should the need arise. Before we do that, open the .gitignore file and add a regular expression pattern of the backup files that your editor creates. In my case that’s Emacs and the backup files have an ending of: *~.

The last command git status states that I’m currently on the main master branch. To do further work, I will create a new branch and do my work within it. Once I’m happy with it, I’ll merge it back into the master branch.

$ git checkout -b hello_world
Switched to a new branch 'hello_world'

With the command git checkout -b helloworld I created a new branch helloworld and switched to it.

The output from git branch confirms it:

$ git branch
* hello_world
master

The initial ‘*’ in front of the branch name states the branch in which I’m currently working.

Hello world in BDD

If the branch name is anything to go by, you probably guessed what the next part of the tutorial will show. The creation of the “Hello world” page.

Since this tutorial tries to teach the usage of Cucumber and Behaviour Driven Development, I’ll start by writing a feature file explaining how I wish my application to behave.

Under the features directory I open a file hello.feature and add:

Feature: hello world
I want the application to greet the world every time I use it
Scenario: greet the world
Given I visit the app
Then it should greet the world

Feature and Scenario are keywords. Feature is the main title, as it were, that briefly outlines what is being described, followed by a description. Scenario is an example of how a particular example should manifest.
There is also a file called add.feature, which isn’t needed, so I’ll remove it:

$ git rm add.feature

Then I run Cucumber, to see the output:

$ bundle exec cucumber
Using the default profile...
Feature: hello world
I want the application to greet the world every time I use it
Scenario: greet the world # features/hello.feature:4
Given I visit the app # features/hello.feature:5
Undefined step: "I visit the app" (Cucumber::Undefined)
features/hello.feature:5:in 'Given I visit the app'
Then it should greet the world # features/hello.feature:6
Undefined step: "it should greet the world" (Cucumber::Undefined)
features/hello.feature:6:in 'Then it should greet the world'
1 scenario (1 undefined)
2 steps (2 undefined)
0m0.002s
You can implement step definitions for undefined steps with these snippets:
Given /^I visit the app$/ do
pending # express the regexp above with the code you wish you had
end
Then /^it should greet the world$/ do
pending # express the regexp above with the code you wish you had
end

The Cucumber complains that it does not recognise the undefined steps. So I copy them and add them to a new file:features/stepdefinitions/hellosteps.rb:

Given /^I visit the app$/ do
pending # express the regexp above with the code you wish you had
end
Then /^it should greet the world$/ do
pending # express the regexp above with the code you wish you had
end

When I run the Cucumber again:

$ bundle exec cucumber
Using the default profile...
Feature: hello world
I want the application to greet the world every time I use it
Scenario: greet the world # features/hello.feature:4
Given I visit the app # features/step_definitions/hello_steps.rb:1
TODO (Cucumber::Pending)
./features/step_definitions/hello_steps.rb:2:in '/^I visit the app$/'
features/hello.feature:5:in 'Given I visit the app'
Then it should greet the world # features/step_definitions/hello_steps.rb:5
1 scenario (1 pending)
2 steps (1 skipped, 1 pending)
0m0.002s

It fails on the first step and skips the second one. Since the first step doesn’t really have anything defined, I add the following:

Given /^I visit the app$/ do
visit '/'
end

and run Cucumber again:

$ bundle exec cucumber
Using the default profile...
Feature: hello world
I want the application to greet the world every time I use it
Scenario: greet the world # features/hello.feature:4
Given I visit the app # features/step_definitions/hello_steps.rb:1
Then it should greet the world # features/step_definitions/hello_steps.rb:5
TODO (Cucumber::Pending)
./features/step_definitions/hello_steps.rb:6:in '/^it should greet the world$/'
features/hello.feature:6:in 'Then it should greet the world'
1 scenario (1 pending)
2 steps (1 pending, 1 passed)
0m0.367s

And the first step in the scenario passes, but the second step is still pending. So I modify it:

Then /^it should greet the world$/ do
page.should have_content("Hello world")
end

then I run Cucumber again:

$ bundle exec cucumber
Using the default profile...
Feature: hello world
I want the application to greet the world every time I use it
Scenario: greet the world # features/hello.feature:4
Given I visit the app # features/step_definitions/hello_steps.rb:1
Then it should greet the world # features/step_definitions/hello_steps.rb:5
undefined local variable or method 'response_body' for #<Object:0x9741db0> (NameError)
./features/step_definitions/hello_steps.rb:6:in '/^it should greet the world$/'
features/hello.feature:6:in `Then it should greet the world'
Failing Scenarios:
cucumber features/hello.feature:4 # Scenario: greet the world
1 scenario (1 failed)
2 steps (1 failed, 1 passed)
0m0.205s

Which is understandable, as I haven’t created anything that can render such greeting.

To rectify that I run:

$ padrino gen controller events index

which in turn creates events.rb under app/controllers and events_controller_spec.rb under spec/app/controllers/.

If you open spec/app/controllers/events_controller_spec.rb you’ll see a default example:

require 'spec_helper'
describe "EventsController" do
before do
get "/"
end
it "returns hello world" do
last_response.body.should == "Hello World"
end
end

which coincidentally is exactly what I’m trying to describe.

When I run the spec, like so:

$ padrino rake spec

it will fail. This is to be expected as I still don’t have anything written yet. To remedy that, I add an index route to the Event controller in app/controllers/events.rb:

Rubytoday.controllers :events do
get :index, :map => "/" do
"Hello world"
end
end

Which fails, but if you look at the example, the only difference is that the example expected the output to be “Hello World” as opposed to “Hello world”. The error is in the spelling. Once I change that…

$ bundle exec cucumber
Using the default profile...
<p>Feature: hello world
I want the application to greet the world every time I use it
Scenario: greet the world # features/hello.feature:4
Given I visit the app # features/step<em>definitions/hello</em>steps.rb:1
Then it should greet the world # features/step<em>definitions/hello</em>steps.rb:5
1 scenario (1 passed)
2 steps (2 passed)
0m0.402s

This concludes the first tutorial in the series. In the next tutorial I will show how to merge content in Git, how to deploy it to Heroku and I’ll carry on building the rest of the app. If this is your first look at Padrino, I’d love to hear what you think in the comments below. All the code can be obtained from here: https://github.com/RubySource/simic_padrino.