Checking for any exception

五迷三道 提交于 2020-01-15 09:09:27

问题


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

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!