Wednesday, March 25, 2009

RSpec with Sinatra & CouchDB

‹prev | My Chain | next›

I left off last night moving into the guts of the application. The plan was to start BDDing with RSpec. It occurred to me, however, that I had no idea how to do it. Happily, Sinatra's testing documentation includes RSpec information.

Based on that documentation, I create spec/eee_spec.rb:
require 'eee'
require 'spec'
require 'spec/interop/test'
require 'sinatra/test'

require 'webrat'
Spec::Runner.configure do |config|
config.include Webrat::Matchers, :type => :views
end

describe 'GET /recipes' do
include Sinatra::Test

before(:all) do
RestClient.put @@db, { }
end

after(:all) do
RestClient.delete @@db
end

before (:each) do
@title = "Recipe Title"
end

it "should include a title" do
get '/recipes/test-recipe'
response.should be_ok
response.should have_selector("h1", :content => @title)
end
end
One addition in there is the inclusion of webrat matchers (because they're so darn nice). I have also included CouchDB build & teardown before(:all) and after(:all) blocks (based on the Cucumber Before and After blocks). Finally, I add a simple test for a title tag (using a Webrat have_selector matcher).

Since I have yet to add anything to the recipes action, I fully expect this example to fail when run:
cstrom@jaynestown:~/repos/eee-code$ ruby ./spec/eee_spec.rb 
F

1)
RestClient::RequestFailed in 'GET /recipes before(:all)'
HTTP status code 412
/home/cstrom/.gem/ruby/1.8/gems/rest-client-0.9.2/lib/restclient/request.rb:144:in `process_result'
/home/cstrom/.gem/ruby/1.8/gems/rest-client-0.9.2/lib/restclient/request.rb:106:in `transmit'
/home/cstrom/.gem/ruby/1.8/gems/rest-client-0.9.2/lib/restclient/request.rb:103:in `transmit'
/home/cstrom/.gem/ruby/1.8/gems/rest-client-0.9.2/lib/restclient/request.rb:36:in `execute_inner'
/home/cstrom/.gem/ruby/1.8/gems/rest-client-0.9.2/lib/restclient/request.rb:28:in `execute'
/home/cstrom/.gem/ruby/1.8/gems/rest-client-0.9.2/lib/restclient/request.rb:12:in `execute'
/home/cstrom/.gem/ruby/1.8/gems/rest-client-0.9.2/lib/restclient.rb:65:in `put'
./spec/eee_spec.rb:15:
./spec/eee_spec.rb:11:

Finished in 0.028201 seconds

0 examples, 1 failure
Indeed it does fail—just not the failure I had expected. Instead of a non-matching text failure, I get a RestClient failure. Experience has taught me to look in the couch.log almost immediately after seeing these and I am not disappointed this time:
[info] [<0.10798.5>] 127.0.0.1 - - 'PUT' /eee 412
Ah, just as with Cucumber, the Sinatra configure :test blocks are not being honored when running RSpec tests. Adding ENV['RACK_ENV'] = 'test' to the top of the eee_spec.rb file (before the require 'eee' statement) resolves that problem:
cstrom@jaynestown:~/repos/eee-code$ ruby ./spec/eee_spec.rb
F

1)
'GET /recipes should include a title' FAILED
expected following output to contain a <h1>Recipe Title</h1> tag:


./spec/eee_spec.rb:31:
./spec/eee_spec.rb:13:

Finished in 0.039395 seconds

1 example, 1 failure
Changing the get '/recipes/:permalink' block to:
get '/recipes/:permalink' do
"<h1>Recipe Title</h1>"
end
resolves the failure.

After some more red-green-refactoring, I end up with the following spec:
  before (:each) do
@date = Date.today
@title = "Recipe Title"
@permalink = @date.to_s + "-" + @title.downcase.gsub(/\W/, '-')

RestClient.put "#{@@db}/#{@permalink}",
{ :title => @title,
:date => @date }.to_json,
:content_type => 'application/json'
end

it "should include a title" do
get "/recipes/#{@permalink}"
response.should be_ok
response.should have_selector("h1", :content => @title)
end
This passes when run against the following get '/recipes/:permalink' block:
get '/recipes/:permalink' do
data = RestClient.get "#{@@db}/#{params[:permalink]}"
result = JSON.parse(data)

"<h1>#{result['title']}</h1>"
end
(tonight's commit of this code)

Tomorrow night: HAML (I think) and more progress on building the innards needed to implement the first Recipe Details scenario.

No comments:

Post a Comment