diff options
Diffstat (limited to 'activesupport/lib/active_support/testing')
4 files changed, 189 insertions, 86 deletions
diff --git a/activesupport/lib/active_support/testing/assertions.rb b/activesupport/lib/active_support/testing/assertions.rb new file mode 100644 index 0000000000..ce2f44efd6 --- /dev/null +++ b/activesupport/lib/active_support/testing/assertions.rb @@ -0,0 +1,61 @@ +module ActiveSupport + module Testing + module Assertions + # Test numeric difference between the return value of an expression as a result of what is evaluated + # in the yielded block. + # + # assert_difference 'Article.count' do + # post :create, :article => {...} + # end + # + # An arbitrary expression is passed in and evaluated. + # + # assert_difference 'assigns(:article).comments(:reload).size' do + # post :create, :comment => {...} + # end + # + # An arbitrary positive or negative difference can be specified. The default is +1. + # + # assert_difference 'Article.count', -1 do + # post :delete, :id => ... + # end + # + # An array of expressions can also be passed in and evaluated. + # + # assert_difference [ 'Article.count', 'Post.count' ], +2 do + # post :create, :article => {...} + # end + # + # A error message can be specified. + # + # assert_difference 'Article.count', -1, "An Article should be destroyed" do + # post :delete, :id => ... + # end + def assert_difference(expressions, difference = 1, message = nil, &block) + expression_evaluations = Array(expressions).collect{ |expression| lambda { eval(expression, block.send(:binding)) } } + + original_values = expression_evaluations.inject([]) { |memo, expression| memo << expression.call } + yield + expression_evaluations.each_with_index do |expression, i| + assert_equal original_values[i] + difference, expression.call, message + end + end + + # Assertion that the numeric result of evaluating an expression is not changed before and after + # invoking the passed in block. + # + # assert_no_difference 'Article.count' do + # post :create, :article => invalid_attributes + # end + # + # A error message can be specified. + # + # assert_no_difference 'Article.count', "An Article should not be destroyed" do + # post :create, :article => invalid_attributes + # end + def assert_no_difference(expressions, message = nil, &block) + assert_difference expressions, 0, message, &block + end + end + end +end diff --git a/activesupport/lib/active_support/testing/declarative.rb b/activesupport/lib/active_support/testing/declarative.rb new file mode 100644 index 0000000000..cb6a5844eb --- /dev/null +++ b/activesupport/lib/active_support/testing/declarative.rb @@ -0,0 +1,21 @@ +module ActiveSupport + module Testing + module Declarative + # test "verify something" do + # ... + # end + def test(name, &block) + test_name = "test_#{name.gsub(/\s+/,'_')}".to_sym + defined = instance_method(test_name) rescue false + raise "#{test_name} is already defined in #{self}" if defined + if block_given? + define_method(test_name, &block) + else + define_method(test_name) do + flunk "No implementation provided for #{name}" + end + end + end + end + end +end diff --git a/activesupport/lib/active_support/testing/deprecation.rb b/activesupport/lib/active_support/testing/deprecation.rb new file mode 100644 index 0000000000..e9220605bd --- /dev/null +++ b/activesupport/lib/active_support/testing/deprecation.rb @@ -0,0 +1,55 @@ +module ActiveSupport + module Testing + module Deprecation #:nodoc: + def assert_deprecated(match = nil, &block) + result, warnings = collect_deprecations(&block) + assert !warnings.empty?, "Expected a deprecation warning within the block but received none" + if match + match = Regexp.new(Regexp.escape(match)) unless match.is_a?(Regexp) + assert warnings.any? { |w| w =~ match }, "No deprecation warning matched #{match}: #{warnings.join(', ')}" + end + result + end + + def assert_not_deprecated(&block) + result, deprecations = collect_deprecations(&block) + assert deprecations.empty?, "Expected no deprecation warning within the block but received #{deprecations.size}: \n #{deprecations * "\n "}" + result + end + + private + def collect_deprecations + old_behavior = ActiveSupport::Deprecation.behavior + deprecations = [] + ActiveSupport::Deprecation.behavior = Proc.new do |message, callstack| + deprecations << message + end + result = yield + [result, deprecations] + ensure + ActiveSupport::Deprecation.behavior = old_behavior + end + end + end +end + +begin + require 'test/unit/error' + + module Test + module Unit + class Error # :nodoc: + # Silence warnings when reporting test errors. + def message_with_silenced_deprecation + ActiveSupport::Deprecation.silence do + message_without_silenced_deprecation + end + end + + alias_method_chain :message, :silenced_deprecation + end + end + end +rescue LoadError + # Using miniunit, ignore. +end diff --git a/activesupport/lib/active_support/testing/setup_and_teardown.rb b/activesupport/lib/active_support/testing/setup_and_teardown.rb index a514b61fea..245f57a7b0 100644 --- a/activesupport/lib/active_support/testing/setup_and_teardown.rb +++ b/activesupport/lib/active_support/testing/setup_and_teardown.rb @@ -1,119 +1,85 @@ +require 'active_support/callbacks' + module ActiveSupport module Testing module SetupAndTeardown - # For compatibility with Ruby < 1.8.6 - PASSTHROUGH_EXCEPTIONS = - if defined?(Test::Unit::TestCase::PASSTHROUGH_EXCEPTIONS) - Test::Unit::TestCase::PASSTHROUGH_EXCEPTIONS - else - [NoMemoryError, SignalException, Interrupt, SystemExit] - end - def self.included(base) base.class_eval do include ActiveSupport::Callbacks define_callbacks :setup, :teardown - if defined?(::Mini) - undef_method :run - alias_method :run, :run_with_callbacks_and_miniunit + if defined? MiniTest + include ForMiniTest else - begin - require 'mocha' - undef_method :run - alias_method :run, :run_with_callbacks_and_mocha - rescue LoadError - undef_method :run - alias_method :run, :run_with_callbacks_and_testunit - end + include ForClassicTestUnit end end end - def run_with_callbacks_and_miniunit(runner) - result = '.' - begin - run_callbacks :setup - result = super - rescue Exception => e - result = runner.puke(self.class, self.name, e) - ensure + module ForMiniTest + def run(runner) + result = '.' begin - teardown - run_callbacks :teardown, :enumerator => :reverse_each + run_callbacks :setup + result = super rescue Exception => e result = runner.puke(self.class, self.name, e) + ensure + begin + run_callbacks :teardown, :enumerator => :reverse_each + rescue Exception => e + result = runner.puke(self.class, self.name, e) + end end + result end - result end - # This redefinition is unfortunate but test/unit shows us no alternative. - def run_with_callbacks_and_testunit(result) #:nodoc: - return if @method_name.to_s == "default_test" + module ForClassicTestUnit + # For compatibility with Ruby < 1.8.6 + PASSTHROUGH_EXCEPTIONS = Test::Unit::TestCase::PASSTHROUGH_EXCEPTIONS rescue [NoMemoryError, SignalException, Interrupt, SystemExit] - yield(Test::Unit::TestCase::STARTED, name) - @_result = result - begin - run_callbacks :setup - setup - __send__(@method_name) - rescue Test::Unit::AssertionFailedError => e - add_failure(e.message, e.backtrace) - rescue *PASSTHROUGH_EXCEPTIONS - raise - rescue Exception - add_error($!) - ensure - begin - teardown - run_callbacks :teardown, :enumerator => :reverse_each - rescue Test::Unit::AssertionFailedError => e - add_failure(e.message, e.backtrace) - rescue *PASSTHROUGH_EXCEPTIONS - raise - rescue Exception - add_error($!) - end - end - result.add_run - yield(Test::Unit::TestCase::FINISHED, name) - end + # This redefinition is unfortunate but test/unit shows us no alternative. + # Doubly unfortunate: hax to support Mocha's hax. + def run(result) + return if @method_name.to_s == "default_test" - # Doubly unfortunate: mocha does the same so we have to hax their hax. - def run_with_callbacks_and_mocha(result) - return if @method_name.to_s == "default_test" + if using_mocha = respond_to?(:mocha_verify) + assertion_counter = Mocha::TestCaseAdapter::AssertionCounter.new(result) + end - yield(Test::Unit::TestCase::STARTED, name) - @_result = result - begin - mocha_setup + yield(Test::Unit::TestCase::STARTED, name) + @_result = result begin - run_callbacks :setup - setup - __send__(@method_name) - mocha_verify { add_assertion } - rescue Mocha::ExpectationError => e - add_failure(e.message, e.backtrace) - rescue Test::Unit::AssertionFailedError => e - add_failure(e.message, e.backtrace) - rescue StandardError, ScriptError - add_error($!) - ensure begin - teardown - run_callbacks :teardown, :enumerator => :reverse_each + run_callbacks :setup + setup + __send__(@method_name) + mocha_verify(assertion_counter) if using_mocha + rescue Mocha::ExpectationError => e + add_failure(e.message, e.backtrace) rescue Test::Unit::AssertionFailedError => e add_failure(e.message, e.backtrace) - rescue StandardError, ScriptError - add_error($!) + rescue Exception => e + raise if PASSTHROUGH_EXCEPTIONS.include?(e.class) + add_error(e) + ensure + begin + teardown + run_callbacks :teardown, :enumerator => :reverse_each + rescue Test::Unit::AssertionFailedError => e + add_failure(e.message, e.backtrace) + rescue Exception => e + raise if PASSTHROUGH_EXCEPTIONS.include?(e.class) + add_error(e) + end end + ensure + mocha_teardown if using_mocha end - ensure - mocha_teardown + result.add_run + yield(Test::Unit::TestCase::FINISHED, name) end - result.add_run - yield(Test::Unit::TestCase::FINISHED, name) end end end |