Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

Test framework refactoring

* Adds test/helper.rb and moves mock_app and other code specific
  to testing the framework out of Sinatra::Test.
* Do not require test/unit. The sinatra/test/unit,
  sinatra/test/spec, and sinatra/test/rspec files can be used to
  choose the framework.
* Add Sinatra::TestHarness, which should act similar to the
  Rack::Session proposal here: http://gist.github.com/41270
* Update the README with information on using the different test
  frameworks.
  • Loading branch information...
commit c00a25ee4168e62b52042acc6d5de37991747fdc 1 parent 9482a91
@rtomayko rtomayko authored
View
30 README.rdoc
@@ -380,59 +380,61 @@ typically don't have to +use+ them explicitly.
== Testing
-=== Test/Unit
+The Sinatra::Test module includes a variety of helper methods for testing
+your Sinatra app. Sinatra includes support for Test::Unit, test-spec, RSpec,
+and Bacon through separate source files.
+
+=== Test::Unit
- require 'rubygems'
require 'sinatra'
require 'sinatra/test/unit'
require 'my_sinatra_app'
class MyAppTest < Test::Unit::TestCase
-
def test_my_default
- get_it '/'
+ get '/'
assert_equal 'My Default Page!', @response.body
end
def test_with_agent
- get_it '/', :agent => 'Songbird'
+ get '/', :agent => 'Songbird'
assert_equal 'You're in Songbird!', @response.body
end
...
-
end
-=== Test/Spec
+=== Test::Spec
+
+Install the test-spec gem and require <tt>'sinatra/test/spec'</tt> before
+your app:
- require 'rubygems'
require 'sinatra'
require 'sinatra/test/spec'
require 'my_sinatra_app'
describe 'My app' do
-
it "should show a default page" do
- get_it '/'
+ get '/'
should.be.ok
body.should.equal 'My Default Page!'
end
...
-
end
=== RSpec
- require 'rubygems'
- require 'spec'
+Install the rspec gem and require <tt>'sinatra/test/rspec'</tt> before
+your app:
+
require 'sinatra'
require 'sinatra/test/rspec'
require 'my_sinatra_app'
describe 'My app' do
it 'should show a default page' do
- get_it '/'
+ get '/'
@response.should be_ok
@response.body.should == 'My Default Page!'
end
View
17 compat/events_test.rb
@@ -1,7 +1,6 @@
require File.dirname(__FILE__) + '/helper'
context "Simple Events" do
-
def simple_request_hash(method, path)
Rack::Request.new({
'REQUEST_METHOD' => method.to_s.upcase,
@@ -14,16 +13,16 @@ class MockResult < Struct.new(:block, :params)
def invoke_simple(path, request_path, &b)
params = nil
- mock_app {
- get path do
- params = self.params
- b.call if b
- end
- }
+ get path do
+ params = self.params
+ b.call if b
+ end
get_it request_path
MockResult.new(b, params)
end
+ setup { Sinatra.application = nil }
+
specify "return last value" do
block = Proc.new { 'Simple' }
result = invoke_simple('/', '/', &block)
@@ -38,6 +37,7 @@ def invoke_simple(path, request_path, &b)
result.params.should.equal "foo" => 'a', "bar" => 'b'
# unscapes
+ Sinatra.application = nil
result = invoke_simple('/:foo/:bar', '/a/blake%20mizerany')
result.should.not.be.nil
result.params.should.equal "foo" => 'a', "bar" => 'blake mizerany'
@@ -48,14 +48,17 @@ def invoke_simple(path, request_path, &b)
result.should.not.be.nil
result.params.should.equal "foo" => 'a', "bar" => 'b'
+ Sinatra.application = nil
result = invoke_simple('/?:foo?/?:bar?', '/a/')
result.should.not.be.nil
result.params.should.equal "foo" => 'a', "bar" => nil
+ Sinatra.application = nil
result = invoke_simple('/?:foo?/?:bar?', '/a')
result.should.not.be.nil
result.params.should.equal "foo" => 'a', "bar" => nil
+ Sinatra.application = nil
result = invoke_simple('/:foo?/?:bar?', '/')
result.should.not.be.nil
result.params.should.equal "foo" => nil, "bar" => nil
View
11 compat/helper.rb
@@ -13,9 +13,18 @@
require 'sinatra/test/unit'
require 'sinatra/test/spec'
+module Sinatra::Test
+ # we need to remove the new test helper methods since they conflict with
+ # the top-level methods of the same name.
+ %w(get head post put delete).each do |verb|
+ remove_method verb
+ end
+ include Sinatra::Delegator
+end
+
class Test::Unit::TestCase
+ include Sinatra::Test
def setup
@app = lambda { |env| Sinatra::Application.call(env) }
end
- include Sinatra::Test
end
View
182 lib/sinatra/test.rb
@@ -1,112 +1,110 @@
require 'sinatra/base'
-require 'test/unit'
-module Sinatra::Test
- include Rack::Utils
-
- attr_reader :app, :request, :response
-
- def mock_app(base=Sinatra::Base, &block)
- @app = Sinatra.new(base, &block)
- end
-
- undef request if method_defined?(:request)
-
- def request(verb, path, *args)
- fail "@app not set - cannot make request" if @app.nil?
- @request = Rack::MockRequest.new(@app)
- opts, input =
- case args.size
- when 2 # input, env
- input, env = args
- if input.kind_of?(Hash) # params, env
- [env, param_string(input)]
+module Sinatra
+
+ module Test
+ include Rack::Utils
+
+ attr_reader :app, :request, :response
+
+ def test_request(verb, path, *args)
+ @app = Sinatra::Application if @app.nil? && defined?(Sinatra::Application)
+ fail "@app not set - cannot make request" if @app.nil?
+ @request = Rack::MockRequest.new(@app)
+ opts, input =
+ case args.size
+ when 2 # input, env
+ input, env = args
+ if input.kind_of?(Hash) # params, env
+ [env, param_string(input)]
+ else
+ [env, input]
+ end
+ when 1 # params
+ if (data = args.first).kind_of?(Hash)
+ env = (data.delete(:env) || {})
+ [env, param_string(data)]
+ else
+ [{}, data]
+ end
+ when 0
+ [{}, '']
else
- [env, input]
+ raise ArgumentError, "zero, one, or two arguments expected"
end
- when 1 # params
- if (data = args.first).kind_of?(Hash)
- env = (data.delete(:env) || {})
- [env, param_string(data)]
- else
- [{}, data]
- end
- when 0
- [{}, '']
- else
- raise ArgumentError, "zero, one, or two arguments expected"
- end
- opts = rack_opts(opts)
- opts[:input] ||= input
- yield @request if block_given?
- @response = @request.request(verb, path, opts)
- end
+ opts = rack_opts(opts)
+ opts[:input] ||= input
+ yield @request if block_given?
+ @response = @request.request(verb, path, opts)
+ end
- def get(path, *args, &b) ; request('GET', path, *args, &b) ; end
- def head(path, *args, &b) ; request('HEAD', path, *args, &b) ; end
- def post(path, *args, &b) ; request('POST', path, *args, &b) ; end
- def put(path, *args, &b) ; request('PUT', path, *args, &b) ; end
- def delete(path, *args, &b) ; request('DELETE', path, *args, &b) ; end
+ def get(path, *args, &b) ; test_request('GET', path, *args, &b) ; end
+ def head(path, *args, &b) ; test_request('HEAD', path, *args, &b) ; end
+ def post(path, *args, &b) ; test_request('POST', path, *args, &b) ; end
+ def put(path, *args, &b) ; test_request('PUT', path, *args, &b) ; end
+ def delete(path, *args, &b) ; test_request('DELETE', path, *args, &b) ; end
- def follow!
- request 'GET', @response.location
- end
+ def follow!
+ test_request 'GET', @response.location
+ end
- def should
- @response.should
- end
+ def body
+ @response.body
+ end
- def body
- @response.body
- end
+ def status
+ @response.status
+ end
- def status
- @response.status
- end
+ RACK_OPT_NAMES = {
+ :accept => "HTTP_ACCEPT",
+ :agent => "HTTP_USER_AGENT",
+ :host => "HTTP_HOST",
+ :session => "HTTP_COOKIE",
+ :cookies => "HTTP_COOKIE",
+ :content_type => "CONTENT_TYPE"
+ }
+
+ def rack_opts(opts)
+ opts.inject({}) do |hash,(key,val)|
+ key = RACK_OPT_NAMES[key] || key
+ hash[key] = val
+ hash
+ end
+ end
- RACK_OPT_NAMES = {
- :accept => "HTTP_ACCEPT",
- :agent => "HTTP_USER_AGENT",
- :host => "HTTP_HOST",
- :session => "HTTP_COOKIE",
- :cookies => "HTTP_COOKIE",
- :content_type => "CONTENT_TYPE"
- }
-
- def rack_opts(opts)
- opts.inject({}) do |hash,(key,val)|
- key = RACK_OPT_NAMES[key] || key
- hash[key] = val
- hash
+ def env_for(opts={})
+ opts = rack_opts(opts)
+ Rack::MockRequest.env_for(opts)
end
- end
- def env_for(opts={})
- opts = rack_opts(opts)
- Rack::MockRequest.env_for(opts)
- end
+ def param_string(hash)
+ hash.map { |pair| pair.map{|v|escape(v)}.join('=') }.join('&')
+ end
- def param_string(hash)
- hash.map { |pair| pair.map{|v|escape(v)}.join('=') }.join('&')
- end
+ if defined? Sinatra::Compat
+ # Deprecated. Use: "get" instead of "get_it".
+ %w(get head post put delete).each do |verb|
+ alias_method "#{verb}_it", verb
+ end
- if defined? Sinatra::Compat
- # Deprecated. Use: "get" instead of "get_it".
- %w(get head post put delete).each do |verb|
- alias_method "#{verb}_it", verb
- remove_method verb
+ # Deprecated. Tests no longer delegate missing methods to the
+ # mock response. Use: @response
+ def method_missing(name, *args, &block)
+ if @response && @response.respond_to?(name)
+ @response.send(name, *args, &block)
+ else
+ super
+ end
+ end
end
+ end
- include Sinatra::Delegator
+ class TestHarness
+ include Test
- # Deprecated. Tests no longer delegate missing methods to the
- # mock response. Use: @response
- def method_missing(name, *args, &block)
- if @response && @response.respond_to?(name)
- @response.send(name, *args, &block)
- else
- super
- end
+ def initialize(app=nil)
+ @app = app || Sinatra::Application
end
end
end
View
7 lib/sinatra/test/rspec.rb
@@ -1,2 +1,9 @@
require 'sinatra/test'
require 'spec/interop/test'
+
+Sinatra::Default.set(
+ :env => :test,
+ :run => false,
+ :raise_errors => true,
+ :logging => false
+)
View
7 lib/sinatra/test/spec.rb
@@ -1,2 +1,9 @@
require 'test/spec'
require 'sinatra/test'
+require 'sinatra/test/unit'
+
+module Sinatra::Test
+ def should
+ @response.should
+ end
+end
View
2  lib/sinatra/test/unit.rb
@@ -1,5 +1,5 @@
-require 'test/unit'
require 'sinatra/test'
+require 'test/unit'
Test::Unit::TestCase.send :include, Sinatra::Test
View
6 test/base_test.rb
@@ -1,10 +1,6 @@
-require 'test/spec'
-require 'sinatra/base'
-require 'sinatra/test'
+require File.dirname(__FILE__) + '/helper'
describe 'Sinatra::Base' do
- include Sinatra::Test
-
it 'includes Rack::Utils' do
Sinatra::Base.should.include Rack::Utils
end
View
6 test/builder_test.rb
@@ -1,10 +1,6 @@
-require 'test/spec'
-require 'sinatra/base'
-require 'sinatra/test'
+require File.dirname(__FILE__) + '/helper'
describe "Builder Templates" do
- include Sinatra::Test
-
def builder_app(&block)
mock_app {
set :views, File.dirname(__FILE__) + '/views'
View
6 test/erb_test.rb
@@ -1,10 +1,6 @@
-require 'test/spec'
-require 'sinatra/base'
-require 'sinatra/test'
+require File.dirname(__FILE__) + '/helper'
describe "ERB Templates" do
- include Sinatra::Test
-
def erb_app(&block)
mock_app {
set :views, File.dirname(__FILE__) + '/views'
View
6 test/filter_test.rb
@@ -1,10 +1,6 @@
-require 'test/spec'
-require 'sinatra/base'
-require 'sinatra/test'
+require File.dirname(__FILE__) + '/helper'
describe "Filters" do
- include Sinatra::Test
-
it "executes filters in the order defined" do
count = 0
mock_app do
View
6 test/haml_test.rb
@@ -1,10 +1,6 @@
-require 'test/spec'
-require 'sinatra/base'
-require 'sinatra/test'
+require File.dirname(__FILE__) + '/helper'
describe "HAML Templates" do
- include Sinatra::Test
-
def haml_app(&block)
mock_app {
set :views, File.dirname(__FILE__) + '/views'
View
16 test/helper.rb
@@ -0,0 +1,16 @@
+require 'test/spec'
+
+$:.unshift File.dirname(File.dirname(__FILE__)) + '/lib'
+require 'sinatra/base'
+require 'sinatra/test'
+require 'sinatra/test/spec'
+
+module Sinatra::Test
+
+ # Sets up a Sinatra::Base subclass defined with the block
+ # given. Used in setup or individual spec methods to establish
+ # the application.
+ def mock_app(base=Sinatra::Base, &block)
+ @app = Sinatra.new(base, &block)
+ end
+end
View
8 test/helpers_test.rb
@@ -1,10 +1,4 @@
-require 'test/spec'
-require 'sinatra/base'
-require 'sinatra/test'
-
-class Test::Unit::TestCase
- include Sinatra::Test
-end
+require File.dirname(__FILE__) + '/helper'
describe 'Sinatra::Helpers' do
describe '#status' do
View
6 test/mapped_error_test.rb
@@ -1,10 +1,6 @@
-require 'test/spec'
-require 'sinatra/base'
-require 'sinatra/test'
+require File.dirname(__FILE__) + '/helper'
describe 'Exception Mappings' do
- include Sinatra::Test
-
class FooError < RuntimeError
end
View
6 test/middleware_test.rb
@@ -1,10 +1,6 @@
-require 'test/spec'
-require 'sinatra/base'
-require 'sinatra/test'
+require File.dirname(__FILE__) + '/helper'
describe "Middleware" do
- include Sinatra::Test
-
before do
@app = mock_app(Sinatra::Default) {
get '/*' do
View
10 test/options_test.rb
@@ -1,13 +1,7 @@
-require 'test/spec'
-require 'sinatra/base'
-require 'sinatra/test'
+require File.dirname(__FILE__) + '/helper'
describe 'Options' do
- include Sinatra::Test
-
- before do
- @app = Class.new(Sinatra::Base)
- end
+ before { @app = Class.new(Sinatra::Base) }
it 'sets options to literal values' do
@app.set(:foo, 'bar')
View
6 test/reload_test.rb
@@ -1,13 +1,9 @@
-require 'test/spec'
-require 'sinatra/base'
-require 'sinatra/test'
+require File.dirname(__FILE__) + '/helper'
$reload_count = 0
$reload_app = nil
describe "Reloading" do
- include Sinatra::Test
-
before {
@app = mock_app(Sinatra::Default)
$reload_app = @app
View
4 test/request_test.rb
@@ -1,6 +1,4 @@
-require 'test/spec'
-require 'sinatra/base'
-require 'sinatra/test'
+require File.dirname(__FILE__) + '/helper'
describe 'Sinatra::Request' do
it 'responds to #user_agent' do
View
6 test/result_test.rb
@@ -1,10 +1,6 @@
-require 'test/spec'
-require 'sinatra/base'
-require 'sinatra/test'
+require File.dirname(__FILE__) + '/helper'
describe 'Result Handling' do
- include Sinatra::Test
-
it "sets response.body when result is a String" do
mock_app {
get '/' do
View
6 test/routing_test.rb
@@ -1,10 +1,6 @@
-require 'test/spec'
-require 'sinatra/base'
-require 'sinatra/test'
+require File.dirname(__FILE__) + '/helper'
describe "Routing" do
- include Sinatra::Test
-
%w[get put post delete head].each do |verb|
it "defines #{verb.upcase} request handlers with #{verb}" do
mock_app {
View
6 test/sass_test.rb
@@ -1,10 +1,6 @@
-require 'test/spec'
-require 'sinatra/base'
-require 'sinatra/test'
+require File.dirname(__FILE__) + '/helper'
describe "Sass Templates" do
- include Sinatra::Test
-
def sass_app(&block)
mock_app {
set :views, File.dirname(__FILE__) + '/views'
View
4 test/sinatra_test.rb
@@ -1,6 +1,4 @@
-require 'test/spec'
-require 'sinatra/base'
-require 'sinatra/test'
+require File.dirname(__FILE__) + '/helper'
describe 'Sinatra' do
it 'creates a new Sinatra::Base subclass on new' do
View
7 test/static_test.rb
@@ -1,13 +1,10 @@
-require 'test/spec'
-require 'sinatra/base'
-require 'sinatra/test'
+require File.dirname(__FILE__) + '/helper'
describe 'Static' do
- include Sinatra::Test
F = ::File
before do
- @app = mock_app {
+ mock_app {
set :static, true
set :public, F.dirname(__FILE__)
}
View
6 test/templates_test.rb
@@ -1,10 +1,6 @@
-require 'test/spec'
-require 'sinatra/base'
-require 'sinatra/test'
+require File.dirname(__FILE__) + '/helper'
describe 'Templating' do
- include Sinatra::Test
-
def render_app(&block)
mock_app {
def render_test(template, data, options, &block)
Please sign in to comment.
Something went wrong with that request. Please try again.