Create a rescue_from matcher for ActionController

This matcher tests that the controller has been set up to rescue from a
specific exception with the ActiveSupport::Rescuable#rescue_from method.
It supports checking for a specific method as well.
This commit is contained in:
Corey Woodcox 2013-04-26 14:34:21 -06:00 committed by Jason Draper
parent 718c8b6dd0
commit 1b5e3abdf9
5 changed files with 150 additions and 0 deletions

View File

@ -1,5 +1,9 @@
# HEAD
* Add a rescue_from matcher for Rails controllers which checks that the correct
ActiveSupport call has been made and that the handlers exist without actually
throwing an exception.
* Changed the scope of AssociationMatcher methods from protected to private.
* Extracted `#order`, `#through`, and `#dependent` from AssociationMatcher as

View File

@ -61,6 +61,7 @@ describe PostsController, "#show" do
it { should respond_with(:success) }
it { should render_template(:show) }
it { should_not set_the_flash }
it { should rescue_from(ActiveRecord::RecordNotFound).with(:render_404) }
end
end
```

View File

@ -6,6 +6,7 @@ require 'shoulda/matchers/action_controller/set_session_matcher'
require 'shoulda/matchers/action_controller/route_matcher'
require 'shoulda/matchers/action_controller/redirect_to_matcher'
require 'shoulda/matchers/action_controller/render_template_matcher'
require 'shoulda/matchers/action_controller/rescue_from_matcher'
module Shoulda
module Matchers

View File

@ -0,0 +1,81 @@
module Shoulda
module Matchers
module ActionController
def rescue_from(exception)
RescueFromMatcher.new exception
end
class RescueFromMatcher
def initialize(exception)
@exception = exception
end
def with(method)
@expected_method = method
self
end
def matches?(controller)
@controller = controller
rescues_from_exception? && method_name_matches? && handler_exists?
end
def description
description = "rescues from #{exception}"
description << " with ##{expected_method}" if expected_method
description
end
def failure_message_for_should
"Expected #{expectation}"
end
def failure_message_for_should_not
"Did not expect #{expectation}"
end
private
attr_reader :controller, :exception, :expected_method, :handlers
def expectation
expectation = "#{controller} to rescue from #{exception}"
if expected_method && !method_name_matches?
expectation << " with ##{expected_method}"
end
unless handler_exists?
expectation << " but #{controller} does not respond to #{expected_method}"
end
expectation
end
def rescues_from_exception?
@handlers = controller.rescue_handlers.select do |handler|
handler.first == exception.to_s
end
handlers.any?
end
def method_name_matches?
if expected_method.present?
handlers.any? do |handler|
handler.last == expected_method
end
else
true
end
end
def handler_exists?
if expected_method.present?
controller.respond_to? expected_method
else
true
end
end
end
end
end
end

View File

@ -0,0 +1,63 @@
require 'spec_helper'
describe Shoulda::Matchers::ActionController::RescueFromMatcher do
context 'a controller that rescues from RuntimeError' do
it "asserts controller is setup with rescue_from" do
controller_with_rescue_from.should rescue_from RuntimeError
end
context 'with a handler method' do
it "asserts rescue_from was set up with handler method" do
controller_with_rescue_from_and_method.should rescue_from(RuntimeError).with(:error_method)
end
it "asserts rescue_from was not set up with incorrect handler method" do
controller_with_rescue_from_and_method.should_not rescue_from(RuntimeError).with(:other_method)
end
it "asserts the controller responds to the handler method" do
matcher = rescue_from(RuntimeError).with(:error_method)
matcher.matches?(controller_with_rescue_from_and_invalid_method).should be_false
matcher.failure_message_for_should.should =~ /does not respond to/
end
end
context 'without a handler method' do
it "the handler method is not included in the description" do
matcher = rescue_from(RuntimeError)
matcher.matches?(controller_with_rescue_from).should be_true
matcher.description.should_not =~ /with #/
end
end
end
context 'a controller that does not rescue from RuntimeError' do
it "asserts controller is not setup with rescue_from" do
matcher = rescue_from RuntimeError
define_controller("RandomController").should_not matcher
matcher.failure_message_for_should_not.should =~ /Did not expect \w+ to rescue from/
end
end
def controller_with_rescue_from
define_controller "RescueRuntimeError" do
rescue_from(RuntimeError) {}
end
end
def controller_with_rescue_from_and_invalid_method
define_controller "RescueRuntimeErrorWithMethod" do
rescue_from RuntimeError, with: :error_method
end
end
def controller_with_rescue_from_and_method
controller = controller_with_rescue_from_and_invalid_method
class << controller
def error_method
true
end
end
controller
end
end