Patches item #8716, was opened at 2007-02-16 19:24 You can respond by visiting: http://rubyforge.org/tracker/?func=detail&atid=1700&aid=8716&group_id=426 Category: Ruby1.8 Group: None Status: Open Resolution: None Priority: 3 Submitted By: Edwin Fine (efine) Assigned to: Nobody (None) Summary: Add option to Test::Unit::Assertions#assert_raise to allow subclasses Initial Comment: The current assert_raise method tests that a specific list of exceptions is raised. This is often overly restrictive, because sometimes one has to allow for the raising of a base exception OR any exception derived from that base exception. This patch adds that functionality by providing an optional last parameter to assert_raise. I did this to preserve DRY and to try to stay backward-compatible. Older test suites should run unchanged. However, newer test suites that include the optional parameter will not run correctly with older test-unit code. This would be a problem even if I added a new method. The last (optional) parameter must be a hash of hashes. The primary hash key must be the symbol :opts. The hash corresponding to that key must contain the entry :allow_subclasses => true. Any other case will revert to the current, more restrictive behavior. If the last parameter is the correct type (hash of hashes) and contains the correct key (:opts), it will be removed from the argument list during assert_raise processing. This will somewhat future-proof the code so that additional parameters could be added if necessary. I patched the trunk version of assertions.rb, but could not get the trunk to compile, so I copied assertions.rb to my 1.85 installation and tested it there with existing unit tests. It seems to work fine. Example: def test_for_nil_ruleset opts = {:opts => { :allow_subclasses => true }} assert_raise Validators::RuleException, opts do validator = Validators::ParamValidation.new(nil) end end Here's the CHANGELOG entry, if you need one: Here's the patch to the trunk version (revision 11764) of assertions.rb: @@ -98,17 +98,39 @@ modules.any? {|mod| actual_exception.is_a?(mod)} end + def _expected_exception_or_subclass?(actual_exception, exceptions, modules) # :nodoc: + exceptions.any? {|cls| actual_exception.class <= cls} or + modules.any? {|mod| actual_exception.is_a?(mod)} + end + ## # Passes if the block raises one of the given exceptions. + # If last argument is a hash with key of :opts, and value + # another hash {<some_sym> => true}, options will be + # processed. Currently there's only one option + # :allow_subclasses, which will make this assertion pass if + # the block raises one of the given exceptions <b>or + # any of their subclasses</b>. # - # Example: + # Examples: # assert_raise RuntimeError, LoadError do # raise 'Boom!!!' # end + # + # opts = {:opts => {:allow_subclasses => true}} + # assert_raise RuntimeError, LoadError, opts do + # raise 'Boom!!!' + # end public def assert_raise(*args) _wrap_assertion do + allow_subclasses = false + if Hash === (opts = args.last) and opts.has_key?(:opts) + args.pop + allow_subclasses = (Hash === opts[:opts] and opts[:opts][:allow_subclasses]) + end + if Module === args.last message = "" else @@ -127,7 +149,13 @@ false end full_message = build_message(message, "<?> exception expected but was\n?", expected, actual_exception) - assert_block(full_message) {_expected_exception?(actual_exception, exceptions, modules)} + assert_block(full_message) do + if allow_subclasses + _expected_exception_or_subclass?(actual_exception, exceptions, modules) + else + _expected_exception?(actual_exception, exceptions, modules) + end + end actual_exception end end Regards, Edwin Fine ---------------------------------------------------------------------- You can respond by visiting: http://rubyforge.org/tracker/?func=detail&atid=1700&aid=8716&group_id=426