Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

Finish up test doc for now [#123]

  • Loading branch information...
commit 11372f2c8475e6a0a5d03a6b885acf83d67f8c34 1 parent 8c053f5
@rtomayko rtomayko authored
Showing with 236 additions and 48 deletions.
  1. +236 −48 testing.markdown
View
284 testing.markdown
@@ -7,99 +7,284 @@ id: testing
Testing with Sinatra
====================
-The `Sinatra::Test` module includes a variety of helper methods
-to test your app.
+Sinatra includes utility classes and modules to assist in testing
+applications. The utilities are based heavily on Rack's
+[`MockRequest`][Rack::MockRequest] and [`MockResponse`][Rack::MockResponse]
+objects — a basic understanding of these classes are highly
+recommended.
-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`.
+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](#frameworks) for information on using Sinatra's test helpers in
+other testing environments.
+
+*NOTE:* There are plenty of apps [in the wild][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"
+ end
+
+ get '/:name' do
+ "Hello #{params[:name]}"
+ end
-However, this document explains how to install Sinatra's test helpers
-intro a variety of testing frameworks.
+Using The `Sinatra::Test` Mixin
+-------------------------------
-Install it
-----------
+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.
-### [Test::Unit][] and [Test::Spec][]
+The following is a simple example that ensures the hello world app functions
+properly:
- require 'test/unit' # or test/spec
+ require 'hello_world'
+ require 'test/unit'
require 'sinatra/test'
- Sinatra::Default.set :environment, :test
- require 'app'
+ 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][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`][Rack::MockRequest] used to generate
+ the request.
+
+ * `response` - A [`Rack::MockResponse`][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][]
-Only the stuff that needs to be required change:
+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
-### [Bacon][]
+ describe 'The HelloWorld App' do
+ include Sinatra::Test
- require 'bacon'
+ 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'
- Sinatra::Default.set :environment, :test
- require 'app'
+ Test::Unit::TestCase.send :include, Sinatra::Test
- class Bacon::Context
- include Sinatra::Test
- end
+### [Bacon][]
-<!-- TODO: Webrat -->
+Testing with Bacon is similar to `test/unit` and RSpec:
-Use it
-------
+ require 'hello_world' # <-- your sinatra app
+ require 'bacon'
+ require 'sinatra/test'
-To be as general as possible, these examples assume `Test::Unit` is being used.
+ set :environment, :test
-*NOTE:* There are plenty of apps [in the wild][wild] that are using other
-testing frameworks.
+ describe 'The HelloWorld App' do
+ include Sinatra::Test
-## app.rb
+ it "says hello" do
+ get '/'
+ response.should.be.ok
+ response.body.should.equal 'Hello World'
+ end
+ end
- require 'sinatra'
+Make `Sinatra::Test` available to all spec contexts by including it in
+`Bacon::Context`:
- get '/' do
- "Hello #{params[:name]}"
+ class Bacon::Context
+ include Sinatra::Test
end
-## test/test\_helpers.rb
+### [Test::Spec][]
- require 'test/unit'
+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'
- Sinatra::Default.set :environment, :test
- require 'app'
+ set :environment, :test
- class Test::Unit::TestCase
+ 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
-## test/app\_test.rb
+Make `Sinatra::Test` available to all spec contexts by including it in
+`Test::Unit::TestCase`:
- require File.dirname(__FILE__) + '/test_helper'
+ require 'test/spec'
+ require 'sinatra/test'
- class MyAppTest < Test::Unit::TestCase
- get test_it_says_hello
- get '/', :name => 'Ryan "Middleware" Tomayko'
- assert body.include?("Middleware")
- end
- end
+ Test::Unit::TestCase.send :include, Sinatra::Test
+
+<!-- TODO: Webrat -->
-<!-- TODO: document usage of get, post etc -->
+See Also
+--------
-See [Sinatra::Test][] and the [accompanying tests][test] for more information
-on `get`, `post`, `delete` and friends.
+See the source for [Sinatra::Test][] and the [accompanying specs][test] for
+more information on `get`, `post`, `put`, `delete` and friends.
[Test::Unit]: http://www.ruby-doc.org/stdlib/libdoc/test/unit/rdoc/classes/Test/Unit.html
[RSpec]: http://rspec.info
@@ -108,3 +293,6 @@ on `get`, `post`, `delete` and friends.
[Sinatra::Test]: http://github.com/sinatra/sinatra/blob/HEAD/lib/sinatra/test.rb
[test]: http://github.com/sinatra/sinatra/blob/HEAD/test/test_test.rb
[wild]: /wild.html
+[spec]: http://rack.rubyforge.org/doc/files/SPEC.html
+[Rack::MockRequest]: http://rack.rubyforge.org/doc/classes/Rack/MockRequest.html
+[Rack::MockResponse]: http://rack.rubyforge.org/doc/classes/Rack/MockResponse.html
Please sign in to comment.
Something went wrong with that request. Please try again.