Forum: Ruby Test::Unit : assert_aborts

72ea925c0ca3d19fdd2f12fa76681624?d=identicon&s=25 Stephan Wehner (stephanwehner)
on 2009-05-24 06:54
Is there an existing way to assert that abort is invoked with
Test::Unit. Here's what I came up with.

Place in "test_helper.rb" for example.

------------------------------------------------------
# Three redefinitions to be able to assert aborts.
class AbortException < Exception
end

class Test::Unit::TestCase
  def assert_aborts(msg_or_pattern)
    asserted = false
    caught_exception = 'none'
    begin
      yield if block_given? # if there is no block, there will not be
any abort
either
    rescue AbortException => e
      caught_exception = e
      if msg_or_pattern.is_a? String
        assert_equal msg_or_pattern, e.to_s.sub(/^[a-z_]*: /,'')
        return
      end
      if msg_or_pattern.is_a? Regexp
        assert_match msg_or_pattern, e.to_s
        return
      end
    end
    flunk "Expected to handle abort with >>#{ msg_or_pattern }<<. Caught
exception >>#{ caught_exception }<< but didn't handle"
  end
end

module Kernel
  def abort(msg)
    raise AbortException.new(msg)
  end
end
------------------------------------------------------

Then in a test

def test_aborting
  assert_aborts 'fatal error encountered' do
    trigger_abort # ....
  end
end




Stephan
753dcb78b3a3651127665da4bed3c782?d=identicon&s=25 Brian Candler (candlerb)
on 2009-05-24 11:22
Have you tried

    assert_raises(AbortException) { ... }

?
72ea925c0ca3d19fdd2f12fa76681624?d=identicon&s=25 Stephan Wehner (stephanwehner)
on 2009-05-24 11:44
Brian Candler wrote:
> Have you tried
>
>     assert_raises(AbortException) { ... }
>
> ?

Thanks -- if you are suggesting to leave out the method assert_aborts: I
thought it might be good to check the abort message. Otherwise, please
let me know.

Stephan
Aee77dba395ece0a04c688b05b07cd63?d=identicon&s=25 Daniel Berger (djberg96)
on 2009-05-24 14:58
(Received via mailing list)
> >
> > ?
>
> Thanks -- if you are suggesting to leave out the method assert_aborts:
> I
> thought it might be good to check the abort message. Otherwise, please
> let me know.

See assert_raise_message in Test::Unit 2.x.

gem install test-unit

Regards,

Dan
72ea925c0ca3d19fdd2f12fa76681624?d=identicon&s=25 Stephan Wehner (stephanwehner)
on 2009-05-24 21:39
Daniel Berger wrote:
>> >
>> > ?
>>
>> Thanks -- if you are suggesting to leave out the method assert_aborts:
>> I
>> thought it might be good to check the abort message. Otherwise, please
>> let me know.
>
> See assert_raise_message in Test::Unit 2.x.
>
> gem install test-unit
>
> Regards,
>
> Dan

Ok thanks. Should I submit patches to Ruby?

 1. assert_aborts through redefining Kernel#abort
 2. assert_raise_message accepts regular expression.

Stephan
4299e35bacef054df40583da2d51edea?d=identicon&s=25 James Gray (bbazzarrakk)
on 2009-05-24 23:06
(Received via mailing list)
On May 24, 2009, at 4:44 AM, Stephan Wehner wrote:

> let me know.
It's possible to check the message even in old versions of
Test::Unit.  For example:

class SpecificError < RuntimeError; end

require "test/unit"

class TestErrorHandling < Test::Unit::TestCase
   def test_error_type_and_message
     error = assert_raise(SpecificError) do
       raise SpecificError, "Magic message goes here..."
     end
     assert_match(/magic/i, error.message)
   end
end

__END__

As for testing for abort(), I wouldn't.  What are you really trying to
figure out, if the code would exit with an error message?  Then check
that.  Throw a StringIO in $stderr and check for a message and see if
Ruby is planning to exit.  abort() raises the same Exception exit
does, so just check for that:

require "test/unit"

class TestErrorHandling < Test::Unit::TestCase
   def test_error_type_and_message
     assert_raise(SystemExit) do
       abort "Bye."
     end
   end
end

__END__

Hope that helps.

James Edward Gray II
72ea925c0ca3d19fdd2f12fa76681624?d=identicon&s=25 Stephan Wehner (stephanwehner)
on 2009-05-25 01:17
James Gray wrote:
> On May 24, 2009, at 4:44 AM, Stephan Wehner wrote:
>
>> let me know.
> It's possible to check the message even in old versions of
> Test::Unit.  For example:
>
> class SpecificError < RuntimeError; end
>
> require "test/unit"
>
> class TestErrorHandling < Test::Unit::TestCase
>    def test_error_type_and_message
>      error = assert_raise(SpecificError) do
>        raise SpecificError, "Magic message goes here..."
>      end
>      assert_match(/magic/i, error.message)
>    end
> end
>
> __END__
>
> As for testing for abort(), I wouldn't.  What are you really trying to
> figure out, if the code would exit with an error message?  Then check
> that.  Throw a StringIO in $stderr and check for a message and see if
> Ruby is planning to exit.  abort() raises the same Exception exit
> does, so just check for that:
>
> require "test/unit"
>
> class TestErrorHandling < Test::Unit::TestCase
>    def test_error_type_and_message
>      assert_raise(SystemExit) do
>        abort "Bye."
>      end
>    end
> end
>
> __END__
>
> Hope that helps.


Ok, thanks a lot!

You mean something like this.


require "test/unit"
require 'stringio'

class TestErrorHandling < Test::Unit::TestCase
  def test_error_type_and_message_II
    assert_aborts(/bye/i) do
      abort "Bye."
    end
  end

private

  def assert_aborts(pattern)
    save_stderr = $stderr
    begin
      $stderr = StringIO.new
      e = assert_raise(SystemExit) do
        yield if block_given?
      end
      assert_match pattern, e.message
    ensure
      $stderr=save_stderr
    end
  end
end

__END__


Stephan

> James Edward Gray II
4299e35bacef054df40583da2d51edea?d=identicon&s=25 James Gray (bbazzarrakk)
on 2009-05-25 05:04
(Received via mailing list)
On May 24, 2009, at 6:17 PM, Stephan Wehner wrote:

>    end
>      end
>      assert_match pattern, e.message
>    ensure
>      $stderr=save_stderr
>    end
>  end
> end
>
> __END__

Sort of like that, yeah.  Basically what I was saying is that I feel
an assert_aborts() method tests an implementation detail.

It doesn't really matter if I use abort() or some output method and
then call exit() myself.  There may be good reasons to do that too,
say if you are printing a complex error message and using printf()
would make it easier to format.

We really just want to know if the user saw an error and if the
program is quitting, so it's better to test for that.

James Edward Gray II
72ea925c0ca3d19fdd2f12fa76681624?d=identicon&s=25 Stephan Wehner (stephanwehner)
on 2009-05-25 08:11
James Gray wrote:
> On May 24, 2009, at 6:17 PM, Stephan Wehner wrote:
>
>>    end
>>      end
>>      assert_match pattern, e.message
>>    ensure
>>      $stderr=save_stderr
>>    end
>>  end
>> end
>>
>> __END__
>
> Sort of like that, yeah.  Basically what I was saying is that I feel
> an assert_aborts() method tests an implementation detail.
>
> It doesn't really matter if I use abort() or some output method and
> then call exit() myself.  There may be good reasons to do that too,
> say if you are printing a complex error message and using printf()
> would make it easier to format.
>
> We really just want to know if the user saw an error and if the
> program is quitting, so it's better to test for that.

Ok, thanks a lot; that makes sense.

Stephan

> James Edward Gray II
58479f76374a3ba3c69b9804163f39f4?d=identicon&s=25 Eric Hodel (Guest)
on 2009-05-26 22:51
(Received via mailing list)
On May 23, 2009, at 21:54, Stephan Wehner wrote:

>      if msg_or_pattern.is_a? String
> exception >>#{ caught_exception }<< but didn't handle"
>  end
> end
>
> module Kernel
>  def abort(msg)
>    raise AbortException.new(msg)
>  end
> end

You're doing far, far too much work!

$ ruby -rstringio -e '$stderr = StringIO.new; begin; abort "hi";
rescue Exception; p $!; end'
#<SystemExit: hi>

Capturing $stderr (then ignoring it) and checking if SystemExit is
raised and has the right message is enough:

$ cat test.rb
require 'minitest/autorun'

class TestA < MiniTest::Unit::TestCase
   def assert_aborts(message)
     e = assert_raises SystemExit do
       capture_io do
         yield
       end
     end

     assert_equal message, e.message
   end

   def test_a
     assert_aborts "hi" do
       abort "hi"
     end
   end
end
$ ruby19 test.rb
Loaded suite test
Started
.
Finished in 0.001654 seconds.

1 tests, 2 assertions, 0 failures, 0 errors, 0 skips
7a6b7d41b5db7c3b1fe3b1f66c256fe9?d=identicon&s=25 David Gamba (Guest)
on 2012-12-19 16:16
(Received via mailing list)
I just found this thread and could only run the code with ruby 1.9.3 but
my
server has 1.8.7 so I needed to tweak it a bit:

require 'test/unit'
require "stringio"

class TestA < Test::Unit::TestCase
   def assert_aborts(message)
     e = assert_raises SystemExit do
        previous_stderr = $stderr
        $stderr = StringIO.new
        yield
     end
    assert_equal message, e.message
    ensure
        $stderr = previous_stderr
    end

   def test_a
     assert_aborts "hi" do
       abort "hi"
     end
   end
end

Also one can change the assert_equal for an assert_match to use a regex.

Thanks :)
Please log in before posting. Registration is free and takes only a minute.
Existing account

NEW: Do you have a Google/GoogleMail, Yahoo or Facebook account? No registration required!
Log in with Google account | Log in with Yahoo account | Log in with Facebook account
No account? Register here.