问题
Using MiniTest spec, I can test that code raises a specific exception as follows:
proc { foo.do_bar }.must_raise SomeException
But, I don't care what the specific exception is, I just want to verify that some exception is thrown. If I, or another developer, decides to change what exception is thrown by Foo#do_bar, my test wouldn't have to change if the expected exception was specified generally enough.
That is, I would like to write the test this way (Exception is an ancestor of class SomeException):
proc { foo.do_bar }.must_raise Exception
By this results in a failure when I run the test:
[Exception] exception expected, not
Class: <SomeException>
Can I write my Minitest spec more generically with regards to exceptions?
(The actual reason I want to check for any exception, rather than a specific exception, is that I'm using a third party Gem, and it is that code that raises the exception. In fact, my method A gets called by third party method B. A raises MyException, however B catches that exception, and re-raises a different exception. This exception has the same message as my exception [and this message is something I ought to verify in the test], but a different class.)
回答1:
describe 'testing' do
it 'must raise' do
a = Proc.new {oo.non_existant}
begin
a[]
rescue => e
end
e.must_be_kind_of Exception
end
end
Regardless, this should do pretty close to what you are asking for.
回答2:
This seems odd behaviour.
From: http://bfts.rubyforge.org/minitest/MiniTest/Assertions.html#method-i-assert_raises
# File lib/minitest/unit.rb, line 337
def assert_raises *exp
msg = "#{exp.pop}\n" if String === exp.last
should_raise = false
begin
yield
should_raise = true
rescue MiniTest::Skip => e
details = "#{msg}#{mu_pp(exp)} exception expected, not"
if exp.include? MiniTest::Skip then
return e
else
raise e
end
rescue Exception => e
details = "#{msg}#{mu_pp(exp)} exception expected, not"
assert(exp.any? { |ex|
ex.instance_of?(Module) ? e.kind_of?(ex) : ex == e.class
}, exception_details(e, details))
return e
end
exp = exp.first if exp.size == 1
flunk "#{msg}#{mu_pp(exp)} expected but nothing was raised." if
should_raise
end
This checks the exception passed is an instance of Module
and if so uses e.kind_of?(ex)
which would work fine as as instance of SomeException
will be of kind Exception
BUT only if ex
is a Module, so Exception
won't work. It needs to be something common that you have mixed into your exceptions.
(As shown here http://ruby-doc.org/core-2.0/Object.html#method-i-kind_of-3F)
This matches minitests own tests ...
module MyModule; end
class AnError < StandardError; include MyModule; end
....
def test_assert_raises
@tc.assert_raises RuntimeError do
raise "blah"
end
end
def test_assert_raises_module
@tc.assert_raises MyModule do
raise AnError
end
end
(From: https://github.com/seattlerb/minitest/blob/master/test/minitest/test_minitest_unit.rb )
So.. if your Exception mixes in a module, you can assert on the module.. but other than that go with @vgoff's answer.. or extend minitest to do what you want.
Note: I love that ruby is all open source!
来源:https://stackoverflow.com/questions/17824502/checking-for-any-exception