Why doesn't MiniTest::Spec have a wont_raise assertion? Why doesn't MiniTest::Spec have a wont_raise assertion? ruby ruby

Why doesn't MiniTest::Spec have a wont_raise assertion?


MiniTest does implement assert_nothing_raised in its Test::Unit compatibility layer, but in its own tests (MiniTest::Unit and MiniTest::Spec) it does not implement any test like this. The reason is, the programmer argues, that testing for nothing raised is not a test of anything; you never expect anything to be raised in a test, except when you are testing for an exception. If an unexpected (uncaught) exception occurs in the code for a test, you'll get an exception reported in good order by the test and you'll know you have a problem.

Example:

require 'minitest/autorun'describe "something" do  it "does something" do    Ooops  endend

Output:

Run options: --seed 41521# Running tests:EFinished 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

Which is exactly what you wanted to know. If you were expecting nothing to be raised, you didn't get it and you've been told so.

So, the argument here is: do not use assert_nothing_raised! It's just a meaningless crutch. See, for example:

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

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

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

On the other hand, clearly assert_nothing_raised corresponds to some intuition among users, since so many people expect a wont_raise to go with must_raise, etc. In particular one would like to focus an assertion on this, not merely a test. Luckily, MiniTest is extremely minimalist and flexible, so if you want to add your own routine, you can. So you can write a method that tests for no exception and returns a known outcome if there is no exception, and now you can assert for that known outcome.

For example (I'm not saying this is perfect, just showing the idea):

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"  endend

The point is not that this is a good or bad idea but that it was never the responsibility of MiniTest to do it for you.


If you need it:

# test_helper.rbmodule Minitest::Assertions  def assert_nothing_raised(*)    yield  endend

And to use it:

def test_unknown_setter  assert_nothing_raised do    result.some_silly_column_name = 'value'  endend


This bothered me enough to dig into the MiniTest sources and provide an implementation in my spec_helper.rb file:

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  endend 

Hope this proves helpful to someone else who also needs wont_raise. Cheers! :)