【问题标题】:Checking for any exception检查任何异常
【发布时间】:2013-07-24 03:04:28
【问题描述】:

使用 MiniTest 规范,我可以测试代码引发特定异常,如下所示:

proc { foo.do_bar }.must_raise SomeException

但是,我不关心具体的异常是什么,我只是想验证是否抛出了 some 异常。如果我或其他开发人员决定更改 Foo#do_bar 抛出的异常,如果预期的异常被指定得足够普遍,我的测试就不必更改。

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

proc { foo.do_bar }.must_raise Exception

这会导致我在运行测试时失败:

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

关于异常,我可以更通用地编写我的 Minitest 规范吗?

(我想检查任何异常而不是特定异常的实际原因是我使用了第三方 Gem,正是该代码引发了异常。事实上,我的方法 A 被调用由第三方方法 B. A 引发 MyException,但是 B 捕获该异常,并重新引发不同的异常。此异常与我的异常具有相同的消息 [并且此消息是我应该在测试中验证的内容],但是不同的类别。)

【问题讨论】:

  • 所以你不在乎是SystemStackError还是SystemExit还是ThreadError?那为什么还要麻烦测试呢?你应该测试细节。否则,您如何与其他开发人员交流您的意图是什么?
  • @vgoff:为简洁起见,我忽略了这一点,但我正在使用 Ruby Racer,它将 JavaScript 绑定到 Ruby,反之亦然。如果我的 Ruby 代码引发异常,该异常最终会作为 RR 类 V8::Error,而不是我的代码引发的异常。这与我正在使用的第三方 Gem 的内部结构有关,这些是我从测试甚至实现的角度不关心的细节。从测试的角度来看,重要的是我的 Ruby 代码检测到无效条件并引发异常。
  • @vgoff 虽然它改变了“为什么”,但据我所知,它并没有改变“如何”。您的第一条评论提出了一个很好的观点,一般来说,在测试时应该是具体的。也就是说,我不想让我的问题过于具体,因为可能有其他人出于某种原因希望使用 MiniTest 测试任何异常。但是,我会在我的问题中添加解释性文字,我为什么要这样做。

标签: ruby minitest


【解决方案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

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

【讨论】:

    【解决方案2】:

    这看起来很奇怪。

    发件人: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

    所以.. 如果您的 Exception 混合在一个模块中,您可以在模块上断言.. 但除此之外,请使用 @vgoff 的答案.. 或扩展 minitest 以做您想做的事情。

    注意:我喜欢 ruby​​ 完全是开源的!

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-02-03
      • 1970-01-01
      相关资源
      最近更新 更多