web-dev-qa-db-ja.com

MiniTest :: Specにwont_raiseアサーションがないのはなぜですか?

RubyのTest::Unitにはassert_nothing_raisedがあります。 Test::UnitMiniTest に置き換えられました。 MiniTestのアサーション/期待がこれに類似していないのはなぜですか?たとえば、must_raiseは期待できますが、wont_raiseは期待できません。

32
matt

MiniTestはTest :: Unit互換性レイヤーにassert_nothing_raisedを実装しますが、独自のテスト(MiniTest::UnitおよびMiniTest::Spec)では実装しませんnotこのようなテストを実装します。その理由は、プログラマーは、何も起こらなかった場合のテストは何のテストでもないと主張しているからです。 for例外をテストしている場合を除いて、テストで何かが発生することを決して期待しません。テストのコードで予期しない(捕捉されなかった)例外が発生した場合、テストによって適切な順序で例外が報告され、問題があることがわかります。

例:

require 'minitest/autorun'

describe "something" do
  it "does something" do
    Ooops
  end
end

出力:

Run options: --seed 41521

# Running tests:

E

Finished tests in 0.000729s, 1371.7421 tests/s, 0.0000 assertions/s.

  1) Error:
test_0001_does_something(something):
NameError: uninitialized constant Ooops
    untitled:5:in `block (2 levels) in <main>'

1 tests, 0 assertions, 0 failures, 1 errors, 0 skips

それはまさにあなたが知りたかったことです。何も起こらないと期待していたのなら、それは得られず、そう言われました。

したがって、ここでの議論は次のとおりです。assert_nothing_raisedを使用しないでください!それはただの無意味な松葉杖です。たとえば、次を参照してください。

https://github.com/seattlerb/minitest/issues/7

https://github.com/seattlerb/minitest/issues/159

http://blog.zenspider.com/blog/2012/01/assert_nothing_tested.html

一方、assert_nothing_raisedwont_raiseと一緒に行くことを期待する人が非常に多いため、明らかにmust_raiseはユーザーの直感に対応します。特にこれに対するアサーションは、単なるテストではありません。幸い、MiniTestは非常にミニマリストで柔軟性があるため、独自のルーチンを追加したい場合は可能です。したがって、例外がないかどうかをテストし、例外がない場合は既知の結果を返すメソッドを作成できます。これで、その既知の結果をアサートできます。

たとえば(これが完璧だと言っているのではなく、アイデアを示しているだけです):

class TestMyRequire < MiniTest::Spec
  def testForError # pass me a block and I'll tell you if it raised
    yield
    "ok"
  rescue
    $!
  end
  it "blends" do
    testForError do
      something_or_other
    end.must_equal "ok"
  end
end

重要なのは、これが良いアイデアでも悪いアイデアでもないということではなく、MiniTestがあなたに代わってそれを行う責任は決してないということです。

48
matt

必要な場合:

# test_helper.rb

module Minitest::Assertions
  def assert_nothing_raised(*)
    yield
  end
end

そしてそれを使用するには:

def test_unknown_setter
  assert_nothing_raised do
    result.some_silly_column_name = 'value'
  end
end
9
dazonic

これは、MiniTestソースを掘り下げて、spec_helper.rbファイルに実装を提供するのに十分な気になりました。

module MiniTest
  module Assertions
    def refute_raises *exp
      msg = "#{exp.pop}.\n" if String === exp.last

      begin
        yield
      rescue MiniTest::Skip => e
        return e if exp.include? MiniTest::Skip
        raise e
      rescue Exception => e
        exp = exp.first if exp.size == 1
        flunk "unexpected exception raised: #{e}"
      end

    end
  end
  module Expectations
    infect_an_assertion :refute_raises, :wont_raise
  end
end 

これがwont_raiseを必要とする他の誰かに役立つことを願っています。乾杯! :)

3
Benji Flaming