2013-07-24 85 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做你想做的。

注:我喜歡這個紅寶石是所有開源的!