Tons of documentation
git-svn-id: https://svn.thoughtbot.com/plugins/shoulda/trunk@146 7bbfaf0e-4d1d-0410-9690-a8bb5f8ef2aa
This commit is contained in:
parent
f00bddd001
commit
0ea1fc75c0
128
README
128
README
|
@ -1,17 +1,123 @@
|
||||||
= ThoughtBot Test Helpers
|
= Shoulda
|
||||||
|
|
||||||
A collection of Test::Unit helper methods.
|
Shoulda makes it easy to write elegant, understandable, and maintainable tests. Shoulda consists of test macros, assertions, and helpers added on to the Test::Unit framework. It's fully compatible with your existing tests, and requires no retooling to use.
|
||||||
|
|
||||||
Adds helpers for
|
Helpers:: #context and #should give you rSpec like test blocks.
|
||||||
|
In addition, you get nested contexts and a much more readable syntax.
|
||||||
|
Macros:: Generate hundreds of lines of Controller and ActiveRecord tests with these powerful macros.
|
||||||
|
They get you started quickly, and can help you ensure that your application is conforming to best practices.
|
||||||
|
Assertions:: Many common rails testing idioms have been distilled into a set of useful assertions.
|
||||||
|
|
||||||
* context and should statements
|
= Usage
|
||||||
* Common ActiveRecord model tests
|
|
||||||
* A few general purpose assertions
|
|
||||||
|
|
||||||
== Todo
|
=== Context Helpers (ThoughtBot::Shoulda::Context)
|
||||||
|
|
||||||
* Many more tests (of the tests). Specifically, the ActiveRecord macros need to be tested.
|
Stop killing your fingers with all of those underscores... Name your tests with plain sentences!
|
||||||
* Controller test helpers
|
|
||||||
* General code cleanups
|
|
||||||
* More options for AR helpers
|
|
||||||
|
|
||||||
|
class UserTest << Test::Unit
|
||||||
|
context "A User instance" do
|
||||||
|
setup do
|
||||||
|
@user = User.find(:first)
|
||||||
|
end
|
||||||
|
|
||||||
|
should "return its full name"
|
||||||
|
assert_equal 'John Doe', @user.full_name
|
||||||
|
end
|
||||||
|
|
||||||
|
context "with a profile" do
|
||||||
|
setup do
|
||||||
|
@user.profile = Profile.find(:first)
|
||||||
|
end
|
||||||
|
|
||||||
|
should "return true when sent #has_profile?"
|
||||||
|
assert @user.has_profile?
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
Produces the following test methods:
|
||||||
|
|
||||||
|
"test: A User instance should return its full name."
|
||||||
|
"test: A User instance with a profile should return true when sent #has_profile?."
|
||||||
|
|
||||||
|
So readable!
|
||||||
|
|
||||||
|
=== ActiveRecord Tests (ThoughtBot::Shoulda::ActiveRecord)
|
||||||
|
|
||||||
|
Quick macro tests for your ActiveRecord associations and validations:
|
||||||
|
|
||||||
|
class PostTest < Test::Unit::TestCase
|
||||||
|
load_all_fixtures
|
||||||
|
|
||||||
|
should_belong_to :user
|
||||||
|
should_have_many :tags, :through => :taggings
|
||||||
|
|
||||||
|
should_require_unique_attributes :title
|
||||||
|
should_require_attributes :body, :message => /wtf/
|
||||||
|
should_require_attributes :title
|
||||||
|
should_only_allow_numeric_values_for :user_id
|
||||||
|
end
|
||||||
|
|
||||||
|
class UserTest < Test::Unit::TestCase
|
||||||
|
load_all_fixtures
|
||||||
|
|
||||||
|
should_have_many :posts
|
||||||
|
|
||||||
|
should_not_allow_values_for :email, "blah", "b lah"
|
||||||
|
should_allow_values_for :email, "a@b.com", "asdf@asdf.com"
|
||||||
|
should_ensure_length_in_range :email, 1..100
|
||||||
|
should_ensure_value_in_range :age, 1..100
|
||||||
|
should_protect_attributes :password
|
||||||
|
end
|
||||||
|
|
||||||
|
Makes TDD so much easier.
|
||||||
|
|
||||||
|
=== Controller Tests (ThoughtBot::Shoulda::Controller::ClassMethods)
|
||||||
|
|
||||||
|
Macros to test the most common controller patterns...
|
||||||
|
|
||||||
|
context "on GET to :show for first record" do
|
||||||
|
setup do
|
||||||
|
get :show, :id => 1
|
||||||
|
end
|
||||||
|
|
||||||
|
should_assign_to :user
|
||||||
|
should_respond_with :success
|
||||||
|
should_render_template :show
|
||||||
|
should_not_set_the_flash
|
||||||
|
|
||||||
|
should "do something else really cool" do
|
||||||
|
assert_equal 1, assigns(:user).id
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
Test entire controllers in a few lines...
|
||||||
|
|
||||||
|
class PostsControllerTest < Test::Unit::TestCase
|
||||||
|
should_be_restful do |resource|
|
||||||
|
resource.parent = :user
|
||||||
|
|
||||||
|
resource.create.params = { :title => "first post", :body => 'blah blah blah'}
|
||||||
|
resource.update.params = { :title => "changed" }
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
should_be_restful generates 40 tests on the fly, for both html and xml requests.
|
||||||
|
|
||||||
|
=== Helpful Assertions (ThoughtBot::Shoulda::General)
|
||||||
|
|
||||||
|
More to come here, but have fun with what's there.
|
||||||
|
|
||||||
|
load_all_fixtures
|
||||||
|
assert_same_elements([:a, :b, :c], [:c, :a, :b])
|
||||||
|
assert_contains(['a', '1'], /\d/)
|
||||||
|
assert_contains(['a', '1'], 'a')
|
||||||
|
|
||||||
|
= Credits
|
||||||
|
|
||||||
|
Shoulda is maintained by {Tammer Saleh}[mailto:tsaleh@thoughtbot.com], and is funded by Thoughtbot[http://www.thoughtbot.com], inc.
|
||||||
|
|
||||||
|
= License
|
||||||
|
|
||||||
|
Shoulda is Copyright © 2006-2007 Tammer Saleh, Thoughtbot. It is free software, and may be redistributed under the terms specified in the README file of the Ruby distribution.
|
|
@ -22,9 +22,9 @@ end
|
||||||
|
|
||||||
require 'shoulda/color' if shoulda_options[:color]
|
require 'shoulda/color' if shoulda_options[:color]
|
||||||
|
|
||||||
module Test # :nodoc:
|
module Test # :nodoc: all
|
||||||
module Unit # :nodoc:
|
module Unit
|
||||||
class TestCase # :nodoc:
|
class TestCase
|
||||||
|
|
||||||
include ThoughtBot::Shoulda::Controller
|
include ThoughtBot::Shoulda::Controller
|
||||||
include ThoughtBot::Shoulda::General
|
include ThoughtBot::Shoulda::General
|
||||||
|
@ -38,10 +38,10 @@ module Test # :nodoc:
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
module ActionController #:nodoc:
|
module ActionController #:nodoc: all
|
||||||
module Integration #:nodoc:
|
module Integration
|
||||||
class Session #:nodoc:
|
class Session
|
||||||
include ThoughtBot::Shoulda::General::InstanceMethods
|
include ThoughtBot::Shoulda::General
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -3,7 +3,7 @@ require 'test/unit/ui/console/testrunner'
|
||||||
# Completely stolen from redgreen gem
|
# Completely stolen from redgreen gem
|
||||||
#
|
#
|
||||||
# Adds colored output to your tests. Specify <tt>color: true</tt> in
|
# Adds colored output to your tests. Specify <tt>color: true</tt> in
|
||||||
# your <tt>test/shoulda.conf</tt> file to enable.
|
# your <tt>~/.shoulda.conf</tt> file to enable.
|
||||||
#
|
#
|
||||||
# *Bug*: for some reason, this adds another line of output to the end of
|
# *Bug*: for some reason, this adds another line of output to the end of
|
||||||
# every rake task, as though there was another (empty) set of tests.
|
# every rake task, as though there was another (empty) set of tests.
|
||||||
|
|
|
@ -2,9 +2,9 @@ module ThoughtBot # :nodoc:
|
||||||
module Shoulda # :nodoc:
|
module Shoulda # :nodoc:
|
||||||
# = context and should blocks
|
# = context and should blocks
|
||||||
#
|
#
|
||||||
# A context block can exist next to normal <tt>def test_blah</tt> statements,
|
# A context block groups should statements under a common setup/teardown method.
|
||||||
# meaning you do not have to fully commit to the context/should syntax in a test file. We have been
|
# Context blocks can be arbitrarily nested, and can do wonders for improving the maintainability
|
||||||
# using this syntax at ThoughtBot, though, and find it very readable.
|
# and readability of your test code.
|
||||||
#
|
#
|
||||||
# A context block can contain setup, should, should_eventually, and teardown blocks.
|
# A context block can contain setup, should, should_eventually, and teardown blocks.
|
||||||
#
|
#
|
||||||
|
@ -20,7 +20,7 @@ module ThoughtBot # :nodoc:
|
||||||
# end
|
# end
|
||||||
# end
|
# end
|
||||||
#
|
#
|
||||||
# This code will produce the method <tt>"test a User instance should return its full name"</tt> (yes, with spaces in the name).
|
# This code will produce the method <tt>"test a User instance should return its full name"</tt>.
|
||||||
#
|
#
|
||||||
# Contexts may be nested. Nested contexts run their setup blocks from out to in before each test.
|
# Contexts may be nested. Nested contexts run their setup blocks from out to in before each test.
|
||||||
# They then run their teardown blocks from in to out after each test.
|
# They then run their teardown blocks from in to out after each test.
|
||||||
|
@ -48,8 +48,11 @@ module ThoughtBot # :nodoc:
|
||||||
# end
|
# end
|
||||||
#
|
#
|
||||||
# This code will produce the following methods
|
# This code will produce the following methods
|
||||||
# * <tt>"test a User instance should return its full name"</tt>
|
# * <tt>"test: a User instance should return its full name."</tt>
|
||||||
# * <tt>"test a User instance with a profile should return true when sent :has_profile?"</tt> (which will have both setup blocks run before it.)
|
# * <tt>"test: a User instance with a profile should return true when sent :has_profile?."</tt>
|
||||||
|
#
|
||||||
|
# <b>A context block can exist next to normal <tt>def test_the_old_way; end</tt> tests</b>,
|
||||||
|
# meaning you do not have to fully commit to the context/should syntax in a test file.
|
||||||
#
|
#
|
||||||
|
|
||||||
module Context
|
module Context
|
||||||
|
@ -59,32 +62,20 @@ module ThoughtBot # :nodoc:
|
||||||
@@teardown_blocks = []
|
@@teardown_blocks = []
|
||||||
end
|
end
|
||||||
|
|
||||||
# Creates a context block with the given name.
|
# Defines a test method. Can be called either inside our outside of a context.
|
||||||
def context(name, &context_block)
|
# Optionally specify <tt>:unimplimented => true</tt> (see should_eventually).
|
||||||
saved_setups = @@setup_blocks.dup
|
#
|
||||||
saved_teardowns = @@teardown_blocks.dup
|
# Example:
|
||||||
saved_contexts = @@context_names.dup
|
#
|
||||||
|
# class UserTest << Test::Unit
|
||||||
@@context_names << name
|
# should "return first user on find(:first)"
|
||||||
context_block.bind(self).call
|
# assert_equal users(:first), User.find(:first)
|
||||||
|
# end
|
||||||
@@context_names = saved_contexts
|
# end
|
||||||
@@setup_blocks = saved_setups
|
#
|
||||||
@@teardown_blocks = saved_teardowns
|
# Would create a test named
|
||||||
end
|
# 'test: should return first user on find(:first)'
|
||||||
|
#
|
||||||
# Run before every should block in the current context
|
|
||||||
def setup(&setup_block)
|
|
||||||
@@setup_blocks << setup_block
|
|
||||||
end
|
|
||||||
|
|
||||||
# Run after every should block in the current context
|
|
||||||
def teardown(&teardown_block)
|
|
||||||
@@teardown_blocks << teardown_block
|
|
||||||
end
|
|
||||||
|
|
||||||
# Defines a test. Can be called either inside our outside of a context.
|
|
||||||
# Optionally specify <tt>:unimplimented => true</tt> (see should_eventually)
|
|
||||||
def should(name, opts = {}, &should_block)
|
def should(name, opts = {}, &should_block)
|
||||||
test_name = ["test:", @@context_names, "should", "#{name}. "].flatten.join(' ').to_sym
|
test_name = ["test:", @@context_names, "should", "#{name}. "].flatten.join(' ').to_sym
|
||||||
|
|
||||||
|
@ -112,8 +103,38 @@ module ThoughtBot # :nodoc:
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# Creates a context block with the given name.
|
||||||
|
def context(name, &context_block)
|
||||||
|
saved_setups = @@setup_blocks.dup
|
||||||
|
saved_teardowns = @@teardown_blocks.dup
|
||||||
|
saved_contexts = @@context_names.dup
|
||||||
|
|
||||||
|
@@context_names << name
|
||||||
|
context_block.bind(self).call
|
||||||
|
|
||||||
|
@@context_names = saved_contexts
|
||||||
|
@@setup_blocks = saved_setups
|
||||||
|
@@teardown_blocks = saved_teardowns
|
||||||
|
end
|
||||||
|
|
||||||
|
# Run before every should block in the current context.
|
||||||
|
# If a setup block appears in a nested context, it will be run after the setup blocks
|
||||||
|
# in the parent contexts.
|
||||||
|
def setup(&setup_block)
|
||||||
|
@@setup_blocks << setup_block
|
||||||
|
end
|
||||||
|
|
||||||
|
# Run after every should block in the current context.
|
||||||
|
# If a teardown block appears in a nested context, it will be run before the teardown
|
||||||
|
# blocks in the parent contexts.
|
||||||
|
def teardown(&teardown_block)
|
||||||
|
@@teardown_blocks << teardown_block
|
||||||
|
end
|
||||||
|
|
||||||
# Defines a specification that is not yet implemented.
|
# Defines a specification that is not yet implemented.
|
||||||
# Will be displayed as an 'X' when running tests, and failures will not be shown.
|
# Will be displayed as an 'X' when running tests, and failures will not be shown.
|
||||||
|
# This is equivalent to:
|
||||||
|
# should(name, {:unimplemented => true}, &block)
|
||||||
def should_eventually(name, &block)
|
def should_eventually(name, &block)
|
||||||
should("eventually #{name}", {:unimplemented => true}, &block)
|
should("eventually #{name}", {:unimplemented => true}, &block)
|
||||||
end
|
end
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
module ThoughtBot # :nodoc:
|
module ThoughtBot # :nodoc:
|
||||||
module Shoulda # :nodoc:
|
module Shoulda # :nodoc:
|
||||||
# = Macro test helpers for your controllers
|
|
||||||
module Controller
|
module Controller
|
||||||
def self.included(other) # :nodoc:
|
def self.included(other) # :nodoc:
|
||||||
other.class_eval do
|
other.class_eval do
|
||||||
|
@ -12,6 +11,30 @@ module ThoughtBot # :nodoc:
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# = Macro test helpers for your controllers
|
||||||
|
#
|
||||||
|
# By using the macro helpers you can quickly and easily create concise and easy to read test suites.
|
||||||
|
#
|
||||||
|
# This code segment:
|
||||||
|
# context "on GET to :show for first record" do
|
||||||
|
# setup do
|
||||||
|
# get :show, :id => 1
|
||||||
|
# end
|
||||||
|
#
|
||||||
|
# should_assign_to :user
|
||||||
|
# should_respond_with :success
|
||||||
|
# should_render_template :show
|
||||||
|
# should_not_set_the_flash
|
||||||
|
#
|
||||||
|
# should "do something else really cool" do
|
||||||
|
# assert_equal 1, assigns(:user).id
|
||||||
|
# end
|
||||||
|
# end
|
||||||
|
#
|
||||||
|
# Would produce 5 tests for the +show+ action
|
||||||
|
#
|
||||||
|
# Furthermore, the should_be_restful helper will create an entire set of tests which will verify that your
|
||||||
|
# controller responds restfully to a variety of requested formats.
|
||||||
module ClassMethods
|
module ClassMethods
|
||||||
# Formats tested by #should_be_restful. Defaults to [:html, :xml]
|
# Formats tested by #should_be_restful. Defaults to [:html, :xml]
|
||||||
VALID_FORMATS = Dir.glob(File.join(File.dirname(__FILE__), 'formats', '*')).map { |f| File.basename(f, '.rb') }.map(&:to_sym) # :doc:
|
VALID_FORMATS = Dir.glob(File.join(File.dirname(__FILE__), 'formats', '*')).map { |f| File.basename(f, '.rb') }.map(&:to_sym) # :doc:
|
||||||
|
@ -20,26 +43,108 @@ module ThoughtBot # :nodoc:
|
||||||
# Actions tested by #should_be_restful
|
# Actions tested by #should_be_restful
|
||||||
VALID_ACTIONS = [:index, :show, :new, :edit, :create, :update, :destroy] # :doc:
|
VALID_ACTIONS = [:index, :show, :new, :edit, :create, :update, :destroy] # :doc:
|
||||||
|
|
||||||
|
# A ResourceOptions object is passed into should_be_restful in order to configure the tests for your controller.
|
||||||
|
#
|
||||||
|
# Example:
|
||||||
|
# class UsersControllerTest < Test::Unit::TestCase
|
||||||
|
# load_all_fixtures
|
||||||
|
#
|
||||||
|
# def setup
|
||||||
|
# ...normal setup code...
|
||||||
|
# @user = User.find(:first)
|
||||||
|
# end
|
||||||
|
#
|
||||||
|
# should_be_restful do |resource|
|
||||||
|
# resource.identifier = :id
|
||||||
|
# resource.klass = User
|
||||||
|
# resource.object = :user
|
||||||
|
# resource.parent = []
|
||||||
|
# resource.actions = [:index, :show, :new, :edit, :update, :create, :destroy]
|
||||||
|
# resource.formats = [:html, :xml]
|
||||||
|
#
|
||||||
|
# resource.create.params = { :name => "bob", :email => 'bob@bob.com', :age => 13}
|
||||||
|
# resource.update.params = { :name => "sue" }
|
||||||
|
#
|
||||||
|
# resource.create.redirect = "user_url(@user)"
|
||||||
|
# resource.update.redirect = "user_url(@user)"
|
||||||
|
# resource.destroy.redirect = "users_url"
|
||||||
|
#
|
||||||
|
# resource.create.flash = /created/i
|
||||||
|
# resource.update.flash = /updated/i
|
||||||
|
# resource.destroy.flash = /removed/i
|
||||||
|
# end
|
||||||
|
# end
|
||||||
|
#
|
||||||
|
# Whenever possible, the resource attributes will be set to sensible defaults.
|
||||||
|
#
|
||||||
class ResourceOptions
|
class ResourceOptions
|
||||||
|
# Configuration options for the create, update, destroy actions under should_be_restful
|
||||||
class ActionOptions
|
class ActionOptions
|
||||||
# String eval'd to get the target of the redirection
|
# String evaled to get the target of the redirection.
|
||||||
|
# All of the instance variables set by the controller will be available to the
|
||||||
|
# evaled code.
|
||||||
|
#
|
||||||
|
# Example:
|
||||||
|
# resource.create.redirect = "user_url(@user.company, @user)"
|
||||||
|
#
|
||||||
|
# Defaults to a generated url based on the name of the controller, the action, and the resource.parents list.
|
||||||
attr_accessor :redirect
|
attr_accessor :redirect
|
||||||
|
|
||||||
# String or Regexp describing a value expected in the flash
|
# String or Regexp describing a value expected in the flash. Will match against any flash key.
|
||||||
|
#
|
||||||
|
# Defaults:
|
||||||
|
# destroy:: /removed/
|
||||||
|
# create:: /created/
|
||||||
|
# update:: /updated/
|
||||||
attr_accessor :flash
|
attr_accessor :flash
|
||||||
|
|
||||||
# Hash describing the params that should be sent in with this action
|
# Hash describing the params that should be sent in with this action.
|
||||||
attr_accessor :params
|
attr_accessor :params
|
||||||
|
end
|
||||||
|
|
||||||
# Actions that should be denied (only used by resource.denied)
|
# Configuration options for the denied actions under should_be_restful
|
||||||
|
#
|
||||||
|
# Example:
|
||||||
|
# context "The public" do
|
||||||
|
# setup do
|
||||||
|
# @request.session[:logged_in] = false
|
||||||
|
# end
|
||||||
|
#
|
||||||
|
# should_be_restful do |resource|
|
||||||
|
# resource.parent = :user
|
||||||
|
#
|
||||||
|
# resource.denied.actions = [:index, :show, :edit, :new, :create, :update, :destroy]
|
||||||
|
# resource.denied.flash = /get outta here/i
|
||||||
|
# resource.denied.redirect = 'new_session_url'
|
||||||
|
# end
|
||||||
|
# end
|
||||||
|
#
|
||||||
|
class DeniedOptions
|
||||||
|
# String evaled to get the target of the redirection.
|
||||||
|
# All of the instance variables set by the controller will be available to the
|
||||||
|
# evaled code.
|
||||||
|
#
|
||||||
|
# Example:
|
||||||
|
# resource.create.redirect = "user_url(@user.company, @user)"
|
||||||
|
attr_accessor :redirect
|
||||||
|
|
||||||
|
# String or Regexp describing a value expected in the flash. Will match against any flash key.
|
||||||
|
#
|
||||||
|
# Example:
|
||||||
|
# resource.create.flash = /created/
|
||||||
|
attr_accessor :flash
|
||||||
|
|
||||||
|
# Actions that should be denied (only used by resource.denied). <i>Note that these actions will
|
||||||
|
# only be tested if they are also listed in +resource.actions+</i>
|
||||||
attr_accessor :actions
|
attr_accessor :actions
|
||||||
end
|
end
|
||||||
|
|
||||||
# Name of key in params that references the primary key. Will almost always be :id (default)
|
# Name of key in params that references the primary key.
|
||||||
|
# Will almost always be :id (default), unless you are using a plugin or have patched rails.
|
||||||
attr_accessor :identifier
|
attr_accessor :identifier
|
||||||
|
|
||||||
# Name of the ActiveRecord class this resource is responsible for. Automatically determined from
|
# Name of the ActiveRecord class this resource is responsible for. Automatically determined from
|
||||||
# test class if not explicitly set.
|
# test class if not explicitly set. UserTest => :user
|
||||||
attr_accessor :klass
|
attr_accessor :klass
|
||||||
|
|
||||||
# Name of the instantiated ActiveRecord object that should be used by some of the tests.
|
# Name of the instantiated ActiveRecord object that should be used by some of the tests.
|
||||||
|
@ -47,33 +152,62 @@ module ThoughtBot # :nodoc:
|
||||||
attr_accessor :object
|
attr_accessor :object
|
||||||
|
|
||||||
# Name of the parent AR objects.
|
# Name of the parent AR objects.
|
||||||
|
#
|
||||||
|
# Example:
|
||||||
|
# # in the routes...
|
||||||
|
# map.resources :companies do
|
||||||
|
# map.resources :people do
|
||||||
|
# map.resources :limbs
|
||||||
|
# end
|
||||||
|
# end
|
||||||
|
#
|
||||||
|
# # in the tests...
|
||||||
|
# class PeopleControllerTest < Test::Unit::TestCase
|
||||||
|
# should_be_restful do |resource|
|
||||||
|
# resource.parent = :companies
|
||||||
|
# end
|
||||||
|
# end
|
||||||
|
#
|
||||||
|
# class LimbsControllerTest < Test::Unit::TestCase
|
||||||
|
# should_be_restful do |resource|
|
||||||
|
# resource.parents = [:companies, :people]
|
||||||
|
# end
|
||||||
|
# end
|
||||||
attr_accessor :parent
|
attr_accessor :parent
|
||||||
alias parents parent
|
alias parents parent
|
||||||
alias parents= parent=
|
alias parents= parent=
|
||||||
|
|
||||||
# Actions that should be tested. Must be a subset of #VALID_ACTIONS
|
# Actions that should be tested. Must be a subset of VALID_ACTIONS (default).
|
||||||
|
# Tests for each actionw will only be generated if the action is listed here.
|
||||||
|
#
|
||||||
|
# Example (for a read-only controller):
|
||||||
|
# resource.actions = [:show, :index]
|
||||||
attr_accessor :actions
|
attr_accessor :actions
|
||||||
|
|
||||||
# Formats that should be tested. Must be a subset of #VALID_FORMATS
|
# Formats that should be tested. Must be a subset of VALID_FORMATS (default).
|
||||||
|
# Each action will be tested against the formats listed here.
|
||||||
|
#
|
||||||
|
# Example:
|
||||||
|
# resource.actions = [:html, :xml]
|
||||||
attr_accessor :formats
|
attr_accessor :formats
|
||||||
|
|
||||||
# ActionOptions object
|
# ActionOptions object specifying options for the create action.
|
||||||
attr_accessor :create
|
attr_accessor :create
|
||||||
|
|
||||||
# ActionOptions object
|
# ActionOptions object specifying options for the update action.
|
||||||
attr_accessor :update
|
attr_accessor :update
|
||||||
|
|
||||||
# ActionOptions object
|
# ActionOptions object specifying options for the desrtoy action.
|
||||||
attr_accessor :destroy
|
attr_accessor :destroy
|
||||||
|
|
||||||
# ActionOptions object
|
# DeniedOptions object specifying which actions should return deny a request, and what should happen in that case.
|
||||||
attr_accessor :denied
|
attr_accessor :denied
|
||||||
|
|
||||||
def initialize # :nodoc:
|
def initialize # :nodoc:
|
||||||
@create = ActionOptions.new
|
@create = ActionOptions.new
|
||||||
@update = ActionOptions.new
|
@update = ActionOptions.new
|
||||||
@destroy = ActionOptions.new
|
@destroy = ActionOptions.new
|
||||||
@denied = ActionOptions.new
|
@denied = DeniedOptions.new
|
||||||
@actions = VALID_ACTIONS
|
@actions = VALID_ACTIONS
|
||||||
@formats = VALID_FORMATS
|
@formats = VALID_FORMATS
|
||||||
@denied.actions = []
|
@denied.actions = []
|
||||||
|
@ -119,7 +253,31 @@ module ThoughtBot # :nodoc:
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
# Bunch of documentation and examples for this one.
|
# :section: should_be_restful
|
||||||
|
# Generates a full suite of tests for a restful controller.
|
||||||
|
#
|
||||||
|
# The following definition will generate tests for the +index+, +show+, +new+,
|
||||||
|
# +edit+, +create+, +update+ and +destroy+ actions, in both +html+ and +xml+ formats:
|
||||||
|
#
|
||||||
|
# should_be_restful do |resource|
|
||||||
|
# resource.parent = :user
|
||||||
|
#
|
||||||
|
# resource.create.params = { :title => "first post", :body => 'blah blah blah'}
|
||||||
|
# resource.update.params = { :title => "changed" }
|
||||||
|
# end
|
||||||
|
#
|
||||||
|
# This generates about 40 tests, all of the format:
|
||||||
|
# "on GET to :show should assign @user."
|
||||||
|
# "on GET to :show should not set the flash."
|
||||||
|
# "on GET to :show should render 'show' template."
|
||||||
|
# "on GET to :show should respond with success."
|
||||||
|
# "on GET to :show as xml should assign @user."
|
||||||
|
# "on GET to :show as xml should have ContentType set to 'application/xml'."
|
||||||
|
# "on GET to :show as xml should respond with success."
|
||||||
|
# "on GET to :show as xml should return <user/> as the root element."
|
||||||
|
# The +resource+ parameter passed into the block is a ResourceOptions object, and
|
||||||
|
# is used to configure the tests for the details of your resources.
|
||||||
|
#
|
||||||
def should_be_restful(&blk) # :yields: resource
|
def should_be_restful(&blk) # :yields: resource
|
||||||
resource = ResourceOptions.new
|
resource = ResourceOptions.new
|
||||||
blk.call(resource)
|
blk.call(resource)
|
||||||
|
@ -138,8 +296,14 @@ module ThoughtBot # :nodoc:
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# :section: Test macros
|
||||||
|
|
||||||
# Macro that creates a test asserting that the flash contains the given value.
|
# Macro that creates a test asserting that the flash contains the given value.
|
||||||
# val can be a String or a Regex
|
# val can be a String or a Regex
|
||||||
|
#
|
||||||
|
# Example:
|
||||||
|
#
|
||||||
|
# should_set_the_flash_to /created/i
|
||||||
def should_set_the_flash_to(val)
|
def should_set_the_flash_to(val)
|
||||||
should "have #{val.inspect} in the flash" do
|
should "have #{val.inspect} in the flash" do
|
||||||
assert_contains flash.values, val, ", Flash: #{flash.inspect}"
|
assert_contains flash.values, val, ", Flash: #{flash.inspect}"
|
||||||
|
@ -154,6 +318,10 @@ module ThoughtBot # :nodoc:
|
||||||
end
|
end
|
||||||
|
|
||||||
# Macro that creates a test asserting that the controller assigned to @name
|
# Macro that creates a test asserting that the controller assigned to @name
|
||||||
|
#
|
||||||
|
# Example:
|
||||||
|
#
|
||||||
|
# should_assign_to :user
|
||||||
def should_assign_to(name)
|
def should_assign_to(name)
|
||||||
should "assign @#{name}" do
|
should "assign @#{name}" do
|
||||||
assert assigns(name.to_sym), "The show action isn't assigning to @#{name}"
|
assert assigns(name.to_sym), "The show action isn't assigning to @#{name}"
|
||||||
|
@ -161,6 +329,10 @@ module ThoughtBot # :nodoc:
|
||||||
end
|
end
|
||||||
|
|
||||||
# Macro that creates a test asserting that the controller did not assign to @name
|
# Macro that creates a test asserting that the controller did not assign to @name
|
||||||
|
#
|
||||||
|
# Example:
|
||||||
|
#
|
||||||
|
# should_not_assign_to :user
|
||||||
def should_not_assign_to(name)
|
def should_not_assign_to(name)
|
||||||
should "not assign to @#{name}" do
|
should "not assign to @#{name}" do
|
||||||
assert !assigns(name.to_sym), "@#{name} was visible"
|
assert !assigns(name.to_sym), "@#{name} was visible"
|
||||||
|
@ -187,8 +359,12 @@ module ThoughtBot # :nodoc:
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# Macro that creates a test asserting that the controller returned a redirect to the given path.
|
||||||
|
# Example:
|
||||||
|
#
|
||||||
|
# should_redirect_to "/"
|
||||||
def should_redirect_to(url)
|
def should_redirect_to(url)
|
||||||
should "redirect to #{url}" do
|
should "redirect to \"#{url}\"" do
|
||||||
instantiate_variables_from_assigns do
|
instantiate_variables_from_assigns do
|
||||||
assert_redirected_to eval(url, self.send(:binding), __FILE__, __LINE__)
|
assert_redirected_to eval(url, self.send(:binding), __FILE__, __LINE__)
|
||||||
end
|
end
|
||||||
|
@ -196,9 +372,9 @@ module ThoughtBot # :nodoc:
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
module InstanceMethods
|
module InstanceMethods # :nodoc:
|
||||||
|
|
||||||
private
|
private # :enddoc:
|
||||||
|
|
||||||
SPECIAL_INSTANCE_VARIABLES = %w{
|
SPECIAL_INSTANCE_VARIABLES = %w{
|
||||||
_cookies
|
_cookies
|
||||||
|
@ -248,11 +424,8 @@ module ThoughtBot # :nodoc:
|
||||||
|
|
||||||
def make_parent_params(resource, record = nil, parent_names = nil) # :nodoc:
|
def make_parent_params(resource, record = nil, parent_names = nil) # :nodoc:
|
||||||
parent_names ||= resource.parents.reverse
|
parent_names ||= resource.parents.reverse
|
||||||
|
|
||||||
return {} if parent_names == [] # Base case
|
return {} if parent_names == [] # Base case
|
||||||
|
|
||||||
parent_name = parent_names.shift
|
parent_name = parent_names.shift
|
||||||
|
|
||||||
parent = record ? record.send(parent_name) : parent_name.to_s.classify.constantize.find(:first)
|
parent = record ? record.send(parent_name) : parent_name.to_s.classify.constantize.find(:first)
|
||||||
|
|
||||||
{ :"#{parent_name}_id" => parent.id }.merge(make_parent_params(resource, parent, parent_names))
|
{ :"#{parent_name}_id" => parent.id }.merge(make_parent_params(resource, parent, parent_names))
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
module ThoughtBot # :nodoc:
|
module ThoughtBot # :nodoc:
|
||||||
module Shoulda # :nodoc:
|
module Shoulda # :nodoc:
|
||||||
module Controller # :nodoc:
|
module Controller # :nodoc:
|
||||||
module XML # :nodoc:
|
module XML
|
||||||
def self.included(other)
|
def self.included(other) #:nodoc:
|
||||||
other.class_eval do
|
other.class_eval do
|
||||||
extend ThoughtBot::Shoulda::Controller::XML::ClassMethods
|
extend ThoughtBot::Shoulda::Controller::XML::ClassMethods
|
||||||
end
|
end
|
||||||
|
@ -27,7 +27,7 @@ module ThoughtBot # :nodoc:
|
||||||
|
|
||||||
protected
|
protected
|
||||||
|
|
||||||
def make_show_xml_tests(res)
|
def make_show_xml_tests(res) # :nodoc:
|
||||||
context "on GET to :show as xml" do
|
context "on GET to :show as xml" do
|
||||||
setup do
|
setup do
|
||||||
request_xml
|
request_xml
|
||||||
|
@ -47,15 +47,15 @@ module ThoughtBot # :nodoc:
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def make_edit_xml_tests(res)
|
def make_edit_xml_tests(res) # :nodoc:
|
||||||
# XML doesn't need an :edit action
|
# XML doesn't need an :edit action
|
||||||
end
|
end
|
||||||
|
|
||||||
def make_new_xml_tests(res)
|
def make_new_xml_tests(res) # :nodoc:
|
||||||
# XML doesn't need a :new action
|
# XML doesn't need a :new action
|
||||||
end
|
end
|
||||||
|
|
||||||
def make_index_xml_tests(res)
|
def make_index_xml_tests(res) # :nodoc:
|
||||||
context "on GET to :index as xml" do
|
context "on GET to :index as xml" do
|
||||||
setup do
|
setup do
|
||||||
request_xml
|
request_xml
|
||||||
|
@ -74,7 +74,7 @@ module ThoughtBot # :nodoc:
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def make_destroy_xml_tests(res)
|
def make_destroy_xml_tests(res) # :nodoc:
|
||||||
context "on DELETE to :destroy as xml" do
|
context "on DELETE to :destroy as xml" do
|
||||||
setup do
|
setup do
|
||||||
request_xml
|
request_xml
|
||||||
|
@ -97,7 +97,7 @@ module ThoughtBot # :nodoc:
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def make_create_xml_tests(res)
|
def make_create_xml_tests(res) # :nodoc:
|
||||||
context "on POST to :create as xml" do
|
context "on POST to :create as xml" do
|
||||||
setup do
|
setup do
|
||||||
request_xml
|
request_xml
|
||||||
|
@ -123,7 +123,7 @@ module ThoughtBot # :nodoc:
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def make_update_xml_tests(res)
|
def make_update_xml_tests(res) # :nodoc:
|
||||||
context "on PUT to :update as xml" do
|
context "on PUT to :update as xml" do
|
||||||
setup do
|
setup do
|
||||||
request_xml
|
request_xml
|
||||||
|
|
|
@ -1,10 +1,10 @@
|
||||||
module ThoughtBot # :nodoc:
|
module ThoughtBot # :nodoc:
|
||||||
module Shoulda # :nodoc:
|
module Shoulda # :nodoc:
|
||||||
module General # :nodoc:
|
module General
|
||||||
def self.included(other)
|
def self.included(other) # :nodoc:
|
||||||
other.class_eval do
|
other.class_eval do
|
||||||
extend ThoughtBot::Shoulda::General::ClassMethods
|
extend ThoughtBot::Shoulda::General::ClassMethods
|
||||||
include ThoughtBot::Shoulda::General::InstanceMethods
|
# include ThoughtBot::Shoulda::General::InstanceMethods
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -18,7 +18,6 @@ module ThoughtBot # :nodoc:
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
module InstanceMethods
|
|
||||||
# Prints a message to stdout, tagged with the name of the calling method.
|
# Prints a message to stdout, tagged with the name of the calling method.
|
||||||
def report!(msg = "")
|
def report!(msg = "")
|
||||||
puts("#{caller.first}: #{msg}")
|
puts("#{caller.first}: #{msg}")
|
||||||
|
@ -83,5 +82,4 @@ module ThoughtBot # :nodoc:
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
Loading…
Reference in New Issue