2013-07-24 52 views
1

使用MINITEST规范,我可以测试代码中引发了一个特定的异常如下:检查任何异常

proc { foo.do_bar }.must_raise SomeException 

但是,我不关心具体的异常是什么,我只是想确认抛出一些异常。如果我或其他开发人员决定更改Foo#do_bar引发的异常,那么如果预期的异常足够一般地指定,我的测试就不必更改。

也就是说,我想这样写测试(例外是类SomeException的祖先):

proc { foo.do_bar }.must_raise Exception 

通过这导致了失败,当我运行测试:

[Exception] exception expected, not 
Class: <SomeException> 

我可以通过关于例外的更一般的方式来编写Minitest规范吗?我想检查任何异常而不是特定异常的实际原因是,我使用的是第三方Gem,它是引发异常的代码。事实上,我的方法A获取由第三方方法B调用.A引发MyException,但B捕获该异常,并重新产生一个不同的异常。这个异常与我的异常[和这个消息是我应该在测试中验证的]相同的消息,但是不同的类别。)

+1

所以你不在乎是否是'SystemStackError'或'SystemExit'或'ThreadError'?那为什么要麻烦测试?你应该测试具体细节。否则,你如何向其他开发者传达你的意图是什么? – vgoff

+0

@vgoff:为了简洁起见,我将其放弃了,但我正在使用Ruby Racer,它将JavaScript绑定到Ruby,反之亦然。如果我的Ruby代码引发了一个异常,这个异常最终会成为一个RR类,V8 :: Error,而不是我的代码引发的异常。这与我正在使用的第三方Gem的内部相关,这些是我从测试甚至实现的角度来看都不关心的细节。从测试的角度来看,重要的是我的Ruby代码检测到无效条件并引发异常。 – Jimothy

+0

@vgoff虽然它改变了“为什么”,但就我所知,它并没有改变“如何”。您在第一条评论中提出了一个很好的观点,那就是一般而言,测试时应该是特定的。也就是说,我不想让我的问题过于具体,因为可能有其他人出于任何原因希望使用MiniTest测试任何异常。但是,我会为我的问题添加解释性文字,为什么我想这样做。 – Jimothy

回答

2
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 

无论如何,这应该做的非常接近你所要求的。

0

这似乎很奇怪的行为。

来源: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 

这将检查传来的例外是Module一个实例,如果是使用e.kind_of?(ex)这将很好地工作作为为SomeException实例都会有种Exception但只有当ex是一个模块,所以Exception将无法​​正常工作。它必须是你常见的东西,你已经混入你的例外。

(如这里http://ruby-doc.org/core-2.0/Object.html#method-i-kind_of-3F所示)

这符合minitests自己的测试...

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 

(来源:https://github.com/seattlerb/minitest/blob/master/test/minitest/test_minitest_unit.rb

所以..如果你的异常模块中混合,你可以断言模块..但除此之外与@ vgoff的答案..或扩展minitest做你想做的。

注:我喜欢这个红宝石是所有开源的!