svrailsconf is a Sinatra App which demonstrates how to attach both Cucumber and RSpec tests to a Sinatra App. Also svrailsconf makes use of these common gems: Haml, Sass, Webrat, and Nokogiri.
If you are new to Sinatra but familiar with Rails then installation of this app should be easy.
First, install these gems:
Sun May 23 13:41 /pt/b/sinatra/svrailsconf maco$ Sun May 23 13:41 /pt/b/sinatra/svrailsconf maco$ Sun May 23 13:41 /pt/b/sinatra/svrailsconf maco$ Sun May 23 13:41 /pt/b/sinatra/svrailsconf maco$ gem list *** LOCAL GEMS *** builder (2.1.2) columnize (0.3.1) configuration (1.1.0) cucumber (0.7.3) diff-lcs (1.1.2) gherkin (1.0.30) haml (3.0.4) heroku (1.9.9) json_pure (1.4.3) launchy (0.3.5) linecache (0.43) mime-types (1.16) nokogiri (1.4.2) rack (1.1.0) rack-test (0.5.3) rake (0.8.7) rest-client (1.4.2) rspec (1.3.0) ruby-debug (0.10.3) ruby-debug-base (0.10.3) sinatra (1.0) term-ansicolor (1.0.5) trollop (1.16.2) webrat (0.7.1) Sun May 23 13:41 /pt/b/sinatra/svrailsconf maco$ Sun May 23 13:41 /pt/b/sinatra/svrailsconf maco$ Sun May 23 13:41 /pt/b/sinatra/svrailsconf maco$
Next, obtain svrailsconf from github:
Sun May 23 13:46 /software maco$ Sun May 23 13:46 /software maco$ cd /tmp Sun May 23 13:46 /tmp maco$ Sun May 23 13:46 /tmp maco$ Sun May 23 13:46 /tmp maco$ git clone [email protected]:bikle/svrailsconf.git Initialized empty Git repository in /private/tmp/svrailsconf/.git/ remote: Counting objects: 32, done. remote: Compressing objects: 100% (26/26), done. remote: Total 32 (delta 2), reused 0 (delta 0) Receiving objects: 100% (32/32), 29.96 KiB, done. Resolving deltas: 100% (2/2), done. Sun May 23 13:46 /tmp maco$ Sun May 23 13:46 /tmp maco$ Sun May 23 13:46 /tmp maco$
Then, start it up:
Sun May 23 13:56 /tmp/svrailsconf maco$ Sun May 23 13:56 /tmp/svrailsconf maco$ cd /tmp Sun May 23 13:56 /tmp maco$ Sun May 23 13:56 /tmp maco$ cd svrailsconf Sun May 23 13:56 /tmp/svrailsconf maco$ Sun May 23 13:56 /tmp/svrailsconf maco$ Sun May 23 13:56 /tmp/svrailsconf maco$ Sun May 23 13:56 /tmp/svrailsconf maco$ ll total 24 drwxr-xr-x 10 maco wheel 340 May 23 13:46 ./ drwxrwxrwt 22 root wheel 748 May 23 13:46 ../ drwxr-xr-x 13 maco wheel 442 May 23 13:46 .git/ -rw-r--r-- 1 maco wheel 1194 May 23 13:46 README.rdoc -rw-r--r-- 1 maco wheel 590 May 23 13:46 app.rb -rw-r--r-- 1 maco wheel 42 May 23 13:46 config.ru drwxr-xr-x 5 maco wheel 170 May 23 13:46 features/ drwxr-xr-x 4 maco wheel 136 May 23 13:46 public/ drwxr-xr-x 4 maco wheel 136 May 23 13:46 spec/ drwxr-xr-x 10 maco wheel 340 May 23 13:46 views/ Sun May 23 13:56 /tmp/svrailsconf maco$ Sun May 23 13:56 /tmp/svrailsconf maco$ Sun May 23 13:56 /tmp/svrailsconf maco$ ruby app.rb == Sinatra/1.0 has taken the stage on 4567 for development with backup from WEBrick [2010-05-23 13:57:04] INFO WEBrick 1.3.1 [2010-05-23 13:57:04] INFO ruby 1.8.7 (2009-06-12) [i686-darwin9.8.0] [2010-05-23 13:57:04] INFO WEBrick::HTTPServer#start: pid=5257 port=4567
And you should see something like this:
http://github.com/bikle/svrailsconf/blob/master/public/images/svrailsconf.png
If you cannot get it to run on your laptop, perhaps you can deploy it to heroku. Here is a demonstration of that idea:
Sun May 23 14:21 /tmp/svrailsconf maco$ Sun May 23 14:21 /tmp/svrailsconf maco$ Sun May 23 14:22 /tmp/svrailsconf maco$ ssh-add -D All identities removed. Sun May 23 14:22 /tmp/svrailsconf maco$ Sun May 23 14:22 /tmp/svrailsconf maco$ ssh-add /pt/b/sinatra/ssh_key.txt Identity added: /pt/b/sinatra/ssh_key.txt (/pt/b/sinatra/ssh_key.txt) Sun May 23 14:23 /tmp/svrailsconf maco$ Sun May 23 14:23 /tmp/svrailsconf maco$ heroku create svrc2010_0523 ! Name must start with a letter and can only contain letters, numbers, and dashes Sun May 23 14:24 /tmp/svrailsconf maco$ heroku create svrc20100523 Creating svrc20100523..... done Created http://svrc20100523.heroku.com/ | [email protected]:svrc20100523.git Git remote heroku added Sun May 23 14:24 /tmp/svrailsconf maco$ Sun May 23 14:24 /tmp/svrailsconf maco$ Sun May 23 14:24 /tmp/svrailsconf maco$ Sun May 23 14:24 /tmp/svrailsconf maco$ Sun May 23 14:24 /tmp/svrailsconf maco$ Sun May 23 14:24 /tmp/svrailsconf maco$ Sun May 23 14:24 /tmp/svrailsconf maco$ git push heroku master Counting objects: 32, done. Compressing objects: 100% (24/24), done. Writing objects: 100% (32/32), 29.99 KiB, done. Total 32 (delta 2), reused 32 (delta 2) -----> Heroku receiving push -----> Sinatra app detected Compiled slug size is 32K -----> Launching..... done http://svrc20100523.heroku.com deployed to Heroku To [email protected]:svrc20100523.git * [new branch] master -> master Sun May 23 14:24 /tmp/svrailsconf maco$ Sun May 23 14:24 /tmp/svrailsconf maco$ Sun May 23 14:24 /tmp/svrailsconf maco$ Sun May 23 14:24 /tmp/svrailsconf maco$ Sun May 23 14:24 /tmp/svrailsconf maco$ Sun May 23 14:24 /tmp/svrailsconf maco$ Sun May 23 14:24 /tmp/svrailsconf maco$ curl http://svrc20100523.heroku.com -o /tmp/my.html % Total % Received % Xferd Average Speed Time Time Time Current Dload Upload Total Spent Left Speed 100 1101 100 1101 0 0 3567 0 --:--:-- --:--:-- --:--:-- 0 Sun May 23 14:25 /tmp/svrailsconf maco$ Sun May 23 14:25 /tmp/svrailsconf maco$ Sun May 23 14:25 /tmp/svrailsconf maco$ Sun May 23 14:25 /tmp/svrailsconf maco$ Sun May 23 14:25 /tmp/svrailsconf maco$ Sun May 23 14:25 /tmp/svrailsconf maco$ Sun May 23 14:25 /tmp/svrailsconf maco$ Sun May 23 14:25 /tmp/svrailsconf maco$ Sun May 23 14:25 /tmp/svrailsconf maco$ head -6 /tmp/my.html <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> <html lang='en-US' xml:lang='en-US' xmlns='http://www.w3.org/1999/xhtml'> <head> <title>SV Ruby Conf 2010</title> </head> <body> Sun May 23 14:26 /tmp/svrailsconf maco$ Sun May 23 14:26 /tmp/svrailsconf maco$ Sun May 23 14:26 /tmp/svrailsconf maco$ Sun May 23 14:26 /tmp/svrailsconf maco$
If you want to learn how to write Cucumber tests for Sinatra Apps, perhaps svrailsconf will be useful. I demonstrate the running of Cucumber tests which have already been written.
First I check that I have the Cucumber gem installed:
Sun May 23 15:48 /tmp/svrailsconf maco$ Sun May 23 15:48 /tmp/svrailsconf maco$ Sun May 23 15:48 /tmp/svrailsconf maco$ gem list cucumber *** LOCAL GEMS *** cucumber (0.7.3) Sun May 23 15:49 /tmp/svrailsconf maco$ Sun May 23 15:49 /tmp/svrailsconf maco$ Sun May 23 15:49 /tmp/svrailsconf maco$
Next, I check that the cucumber command is in my PATH:
Sun May 23 15:49 /tmp/svrailsconf maco$ Sun May 23 15:49 /tmp/svrailsconf maco$ Sun May 23 15:49 /tmp/svrailsconf maco$ which cucumber /Users/maco/.rvm/gems/ruby-1.8.7-p174%sinatra/bin/cucumber Sun May 23 15:49 /tmp/svrailsconf maco$ Sun May 23 15:49 /tmp/svrailsconf maco$ Sun May 23 15:49 /tmp/svrailsconf maco$
Cucumber runs tests controlled by Gherkin which is a language (written by product managers hopefully) inside files with the suffix “feature”. A file named “hello.feature” is listed below:
Sun May 23 15:49 /tmp/svrailsconf maco$ Sun May 23 15:49 /tmp/svrailsconf maco$ Sun May 23 15:49 /tmp/svrailsconf maco$ ll features/ total 8 drwxr-xr-x 5 maco wheel 170 May 23 13:46 ./ drwxr-xr-x 11 maco wheel 374 May 23 15:47 ../ -rw-r--r-- 1 maco wheel 346 May 23 13:46 hello.feature drwxr-xr-x 3 maco wheel 102 May 23 13:46 step_definitions/ drwxr-xr-x 3 maco wheel 102 May 23 13:46 support/ Sun May 23 15:49 /tmp/svrailsconf maco$ Sun May 23 15:49 /tmp/svrailsconf maco$ Sun May 23 15:49 /tmp/svrailsconf maco$ cat features/hello.feature Feature: See Homepage In order to verify loading of homepage As Dan I want to see the homepage Scenario: Load the homepage Given That I am "Dan" When I am on the homepage Then I should see "SV Rails Conf" And I should see the png: svtrain.png And On LHS I should see links: "Home Program Venue Speakers Registration" Sun May 23 15:49 /tmp/svrailsconf maco$ Sun May 23 15:49 /tmp/svrailsconf maco$
We can see that the language of Gherkin is very simple when compared to a computer language like Ruby or JavaScript. The author of Cucumber intends that you ask the Product Manager of your app to write the Gherkin inside of “feature” files.
After I wrote hello.feature, I wanted it to “drive” my app. I see this as like a robot connecting to the app and my hello.feature file controls the robot. The way this is implemented is the Gherkin syntax in hello.feature needs to get translated into Ruby syntax. Once the translation is done, the Ruby syntax is the thing which drives the app.
For example I could have this Gherkin command:
When I am on the homepage
As a Cucumber “expert” I know that the above command needs to get translated to this Ruby command:
@rspns= get "/"
So a key idea there is that if you want to use Cucumber to test your apps you need to know how to translate Gherkin into Ruby. One thing which helps you is that you are not writing low-level Ruby; you are writing Ruby which makes calls to APIs which are powerful yet simple.
Another idea to understand is that translation from Gherkin to Ruby requires that you have a mechanism to map each Gherkin statement to some Ruby code.
You can see how this is done if you study this file:
github.com/bikle/svrailsconf/blob/master/features/step_definitions/some_steps.rb
The above file suggests that if we want to map this Gherkin command:
When I am on the homepage
To this Ruby command:
@rspns= get "/"
Then we need to have some syntax like this in some_steps.rb:
When /^I am on the homepage$/ do @rspns= get "/" end
As you gain experience with Cucumber, Gherkin, and the API calls resident within the features/step_definitions/ files, your Ruby syntax will become more thorough at testing your app.
You can see that by studying the Ruby syntax which is derived from the Gherkin command:
When I am on the homepage
So, here is some information about how I have translated Gherkin into Ruby for this app:
Sun May 23 15:49 /tmp/svrailsconf maco$ Sun May 23 15:49 /tmp/svrailsconf maco$ Sun May 23 15:49 /tmp/svrailsconf maco$ Sun May 23 15:49 /tmp/svrailsconf maco$ ll features/step_definitions/ total 8 drwxr-xr-x 3 maco wheel 102 May 23 13:46 ./ drwxr-xr-x 5 maco wheel 170 May 23 13:46 ../ -rw-r--r-- 1 maco wheel 1238 May 23 13:46 some_steps.rb Sun May 23 15:49 /tmp/svrailsconf maco$ Sun May 23 15:49 /tmp/svrailsconf maco$ Sun May 23 15:49 /tmp/svrailsconf maco$ cat features/step_definitions/some_steps.rb Given /^That I am "([^\"]*)"$/ do |arg1| # Anyone will make this test pass end When /^I am on the homepage$/ do # Here is the Nokogiri way: @rspns= get "/" @ndoc= Nokogiri::HTML(@rspns.body) # Here is the webrat way: visit "/" end Then /^I should see "([^\"]*)"$/ do |arg1| # @ndoc.css("h1")[0].content.should match /Haml on Sinatra Example/ @ndoc.css("h1")[0].content.should match(Regexp.new(arg1)) # Here is the webrat way: last_response.should contain(arg1) last_response.should have_selector("div#header h1") last_response.should have_xpath("//body/table/tr/td/div[@id='header']/h1") end Then /^I should see the png: svtrain\.png$/ do # Here is the Nokogiri way: @ndoc.xpath("//img[@id='svtrain']/@src")[0].value.should== "/images/svtrain.png" # Here is the webrat way: last_response.should have_selector("body table tr td img#svtrain") last_response.should have_xpath("//body/table/tr/td/img[@id='svtrain'][@src='/images/svtrain.png']") end Then /^On LHS I should see links: "([^\"]*)"$/ do |arg1| links_from_dot_feature= arg1.split lhs_links_from_page= @ndoc.css("table tr#tr_two td#td_lhs a").map{ |ae| ae.content} lhs_links_from_page.sort.should== links_from_dot_feature.sort end Sun May 23 15:49 /tmp/svrailsconf maco$ Sun May 23 15:49 /tmp/svrailsconf maco$ Sun May 23 15:49 /tmp/svrailsconf maco$
If you are an experienced programmer, you will see that I am using code which makes API calls dependent on these APIs and technologies:
So, now that I have described my understanding of Cucumber, how do we actually run a Cucumber test? The screen-dump below demonstrates how to run a Cucumber test:
Sun May 23 17:16 /tmp/svrailsconf maco$ Sun May 23 17:16 /tmp/svrailsconf maco$ gem list cucumber *** LOCAL GEMS *** cucumber (0.7.3) Sun May 23 17:16 /tmp/svrailsconf maco$ Sun May 23 17:16 /tmp/svrailsconf maco$ which cucumber /Users/maco/.rvm/gems/ruby-1.8.7-p174%sinatra/bin/cucumber Sun May 23 17:17 /tmp/svrailsconf maco$ Sun May 23 17:17 /tmp/svrailsconf maco$ Sun May 23 17:17 /tmp/svrailsconf maco$ cucumber features/hello.feature Feature: See Homepage In order to verify loading of homepage As Dan I want to see the homepage Scenario: Load the homepage # features/hello.feature:6 Given That I am "Dan" # features/step_definitions/some_steps.rb:2 When I am on the homepage # features/step_definitions/some_steps.rb:6 Then I should see "SV Rails Conf" # features/step_definitions/some_steps.rb:14 And I should see the png: svtrain.png # features/step_definitions/some_steps.rb:24 And On LHS I should see links: "Home Program Venue Speakers Registration" # features/step_definitions/some_steps.rb:33 1 scenario (1 passed) 5 steps (5 passed) 0m0.052s Sun May 23 17:17 /tmp/svrailsconf maco$
Suppose that your app has no product manager. Perhaps your app only has you and that you are the developer? In that case if the app is simple it might make sense to test your app only with RSpec. When you test an app with RSpec the tests are written in Ruby.
Unlike Cucumber, with RSpec you do not need to write step_definition files to translate Gherkin into Ruby.
Here is the URL to the RSpec file I wrote to test this app:
github.com/bikle/svrailsconf/blob/master/spec/app_spec.rb
When you study syntax in the above RSpec file and compare it to Gherkin and Ruby syntax in the Cucumber related files, it should be obvious that writing tests in RSpec is easier.
A screen dump of the syntax to run the RSpec tests is displayed below:
Sun May 23 17:54 /pt/b/sinatra/svrailsconf maco$ Sun May 23 17:54 /pt/b/sinatra/svrailsconf maco$ Sun May 23 17:54 /pt/b/sinatra/svrailsconf maco$ Sun May 23 17:54 /pt/b/sinatra/svrailsconf maco$ gem list rspec *** LOCAL GEMS *** rspec (1.3.0) Sun May 23 17:55 /pt/b/sinatra/svrailsconf maco$ Sun May 23 17:55 /pt/b/sinatra/svrailsconf maco$ Sun May 23 17:55 /pt/b/sinatra/svrailsconf maco$ Sun May 23 17:55 /pt/b/sinatra/svrailsconf maco$ which spec /Users/maco/.rvm/gems/ruby-1.8.7-p174%sinatra/bin/spec Sun May 23 17:55 /pt/b/sinatra/svrailsconf maco$ Sun May 23 17:55 /pt/b/sinatra/svrailsconf maco$ Sun May 23 17:55 /pt/b/sinatra/svrailsconf maco$ Sun May 23 17:55 /pt/b/sinatra/svrailsconf maco$ Sun May 23 17:55 /pt/b/sinatra/svrailsconf maco$ Sun May 23 17:55 /pt/b/sinatra/svrailsconf maco$ Sun May 23 17:55 /pt/b/sinatra/svrailsconf maco$ spec spec/app_spec.rb ... Finished in 0.017241 seconds 3 examples, 0 failures Sun May 23 17:55 /pt/b/sinatra/svrailsconf maco$ Sun May 23 17:55 /pt/b/sinatra/svrailsconf maco$ Sun May 23 17:55 /pt/b/sinatra/svrailsconf maco$
Perhaps it should be noted that the name of the gem is “rspec”, the name of the executable is “spec” and the directory which holds the RSpec file(s) is “spec”.