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.
This commit is contained in:
parent
9482a913a1
commit
c00a25ee41
30
README.rdoc
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
|
||||
|
|
|
@ -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 @@ context "Simple Events" do
|
|||
|
||||
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 @@ context "Simple Events" do
|
|||
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 @@ context "Simple Events" do
|
|||
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
|
||||
|
|
|
@ -13,9 +13,18 @@ require 'sinatra/test'
|
|||
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
|
||||
|
|
|
@ -1,112 +1,110 @@
|
|||
require 'sinatra/base'
|
||||
require 'test/unit'
|
||||
|
||||
module Sinatra::Test
|
||||
include Rack::Utils
|
||||
module Sinatra
|
||||
|
||||
attr_reader :app, :request, :response
|
||||
module Test
|
||||
include Rack::Utils
|
||||
|
||||
def mock_app(base=Sinatra::Base, &block)
|
||||
@app = Sinatra.new(base, &block)
|
||||
end
|
||||
attr_reader :app, :request, :response
|
||||
|
||||
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)]
|
||||
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"
|
||||
opts = rack_opts(opts)
|
||||
opts[:input] ||= input
|
||||
yield @request if block_given?
|
||||
@response = @request.request(verb, path, opts)
|
||||
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!
|
||||
test_request 'GET', @response.location
|
||||
end
|
||||
|
||||
def body
|
||||
@response.body
|
||||
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
|
||||
opts = rack_opts(opts)
|
||||
opts[:input] ||= input
|
||||
yield @request if block_given?
|
||||
@response = @request.request(verb, path, opts)
|
||||
end
|
||||
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 env_for(opts={})
|
||||
opts = rack_opts(opts)
|
||||
Rack::MockRequest.env_for(opts)
|
||||
end
|
||||
|
||||
def follow!
|
||||
request 'GET', @response.location
|
||||
end
|
||||
def param_string(hash)
|
||||
hash.map { |pair| pair.map{|v|escape(v)}.join('=') }.join('&')
|
||||
end
|
||||
|
||||
def should
|
||||
@response.should
|
||||
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
|
||||
|
||||
def body
|
||||
@response.body
|
||||
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
|
||||
# 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
|
||||
|
||||
def env_for(opts={})
|
||||
opts = rack_opts(opts)
|
||||
Rack::MockRequest.env_for(opts)
|
||||
end
|
||||
class TestHarness
|
||||
include Test
|
||||
|
||||
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
|
||||
remove_method verb
|
||||
end
|
||||
|
||||
include Sinatra::Delegator
|
||||
|
||||
# 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
|
||||
|
|
|
@ -1,2 +1,9 @@
|
|||
require 'sinatra/test'
|
||||
require 'spec/interop/test'
|
||||
|
||||
Sinatra::Default.set(
|
||||
:env => :test,
|
||||
:run => false,
|
||||
:raise_errors => true,
|
||||
:logging => false
|
||||
)
|
||||
|
|
|
@ -1,2 +1,9 @@
|
|||
require 'test/spec'
|
||||
require 'sinatra/test'
|
||||
require 'sinatra/test/unit'
|
||||
|
||||
module Sinatra::Test
|
||||
def should
|
||||
@response.should
|
||||
end
|
||||
end
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
require 'test/unit'
|
||||
require 'sinatra/test'
|
||||
require 'test/unit'
|
||||
|
||||
Test::Unit::TestCase.send :include, Sinatra::Test
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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'
|
||||
|
|
|
@ -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'
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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'
|
||||
|
|
|
@ -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
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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')
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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'
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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__)
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
|
|
Loading…
Reference in New Issue