Skip to content
Find file
Fetching contributors…
Cannot retrieve contributors at this time
295 lines (214 sloc) 8.54 KB
title layout id
Testing with Sinatra
default
testing

Testing with Sinatra

Sinatra includes utility classes and modules to assist in testing applications. The utilities are based heavily on Rack's MockRequest and MockResponse objects — a basic understanding of these classes are highly recommended.

All examples in the following sections assume that Test::Unit is being used in an attempt to be as general as possible. See the Test Framework Examples for information on using Sinatra's test helpers in other testing environments.

NOTE: There are plenty of apps in the wild that are using other testing frameworks.

Example App: hello_world.rb

The following example app is used to illustrate testing features. This is assumed to be in a file named hello_world.rb:

require 'sinatra'

get '/' do
  "Hello World #{params[:name]}".strip
end

Using The Sinatra::Test Mixin

The Sinatra::Test module includes a variety of helper methods for simulating requests against an application and asserting expectations about the response. It's typically included directly within the test context and makes a slew of helper methods and attributes available.

The following is a simple example that ensures the hello world app functions properly:

require 'hello_world'
require 'test/unit'
require 'sinatra/test'

set :environment, :test

class HelloWorldTest < Test::Unit::TestCase
  include Sinatra::Test

  def test_it_says_hello_world
    get '/'
    assert response.ok?
    assert_equal 'Hello World', response.body
  end

  def test_it_says_hello_to_a_person
    get '/', :name => 'Simon'
    assert response.body.include?('Simon')
  end
end

Sinatra::Test's Mock Request Methods

The get, put, post, delete, and head methods simulate the respective type of request on the application. Tests typically begin with a call to one of these methods followed by one or more assertions against the resulting response.

All mock request methods have the same argument signature:

get '/path', params={}, rack_env={}
  • /path is the request path and may optionally include a query string.

  • params is a Hash of query/post parameters, a String request body, or nil.

  • rack_env is a Hash of Rack environment values. This can be used to set request headers and other request related information, such as session data. See the Rack SPEC for more information on possible key/values.

Asserting Expectations About The Response

Once a request method has been invoked, the following attributes are available for making assertions:

  • app - The Sinatra application class that handled the mock request.

  • request - The Rack::MockRequest used to generate the request.

  • response - A Rack::MockResponse instance with information on the response generated by the application.

Assertions are typically made against the response object. Because this is so often the case, the Sinatra::Test module forwards missing methods directly to the response object, making assertions against the response especially terse. Consider the following examples:

def test_it_says_hello_world
  get '/'
  assert response.ok?
  assert_equal 'Hello World'.length.to_s, response.header['Content-Length']
  assert_equal 'Hello World', response.body
end

And with the response references removed:

def test_it_says_hello_world
  get '/'
  assert ok?
  assert_equal 'Hello World'.length.to_s, header['Content-Length']
  assert_equal 'Hello World', body
end

Optional Test Setup

The Sinatra::Test mock request methods send requests to @app. If no @app variable is set, the Sinatra::Application class (this is the default application defined at the top-level) is assumed to be the target of requests.

If you're testing a modular application that has multiple Sinatra::Base subclasses, simply set the @app instance variable in the test's setup method or before calling a mock request method:

  def setup
    @app = MySinatraApp
  end

Making Sinatra::Test available to all test cases

If you'd like the Sinatra::Test methods to be available to all test cases without having to include it each time, you can include the Sinatra::Test module in the Test::Unit::TestCase class:

require 'test/unit'
require 'sinatra/test'

class Test::Unit::TestCase
  include Sinatra::Test
end

Now all TestCase subclasses will automatically have Sinatra::Test available to them.

Using Sinatra::TestHarness

The Sinatra::TestHarness class works exactly like the Sinatra::Test module but moves all mock request methods and the request/response objects into a separate context so they're clearly separated from your test context. Although slightly more verbose, some feel this separation results in tests that are easier to understand and maintain.

require 'hello_world'
require 'test/unit'
require 'sinatra/test'

set :environment, :test

class HelloWorldTest < Test::Unit::TestCase
  def setup
    @client = Sinatra::TestHarness.new(Sinatra::Application)
  end

  def test_it_says_hello_world
    response = @client.get('/')
    assert response.ok?
    assert_equal 'Hello World'.length.to_s, response.header['Content-Length']
    assert_equal 'Hello World', response.body
  end

  ...
end

Test Framework Examples {#frameworks}

As of version 0.9.1, Sinatra no longer provides testing framework-specific helpers. Those found in sinatra/test/*.rb are deprecated and will be removed in Sinatra 1.0.

RSpec

Sinatra can be tested under RSpec using the spec/interop library. The Sinatra::Test module should be included within the describe block:

require 'hello_world'  # <-- your sinatra app
require 'spec'
require 'spec/interop/test'
require 'sinatra/test'

set :environment, :test

describe 'The HelloWorld App' do
  include Sinatra::Test

  it "says hello" do
    get '/'
    response.should be_ok
    response.body.should == 'Hello World'
  end
end

Make Sinatra::Test available to all spec contexts by including it in Test::Unit::TestCase:

require 'spec'
require 'spec/interop/test'
require 'sinatra/test'

Test::Unit::TestCase.send :include, Sinatra::Test

Bacon

Testing with Bacon is similar to test/unit and RSpec:

require 'hello_world'  # <-- your sinatra app
require 'bacon'
require 'sinatra/test'

set :environment, :test

describe 'The HelloWorld App' do
  include Sinatra::Test

  it "says hello" do
    get '/'
    response.should.be.ok
    response.body.should.equal 'Hello World'
  end
end

Make Sinatra::Test available to all spec contexts by including it in Bacon::Context:

class Bacon::Context
  include Sinatra::Test
end

Test::Spec

The Sinatra::Test module should be included within the context of the describe block:

require 'hello_world'  # <-- your sinatra app
require 'test/spec'
require 'sinatra/test'

set :environment, :test

describe 'The HelloWorld App' do
  include Sinatra::Test

  it "says hello" do
    get '/'
    response.should.be.ok
    response.body.should.equal 'Hello World'
  end
end

Make Sinatra::Test available to all spec contexts by including it in Test::Unit::TestCase:

require 'test/spec'
require 'sinatra/test'

Test::Unit::TestCase.send :include, Sinatra::Test

See Also

See the source for Sinatra::Test and the accompanying specs for more information on get, post, put, delete and friends.

Something went wrong with that request. Please try again.