Proper Assert_Raise Unit Testing and Use of Exception Class
Asked Answered
O

2

12

I am working on Exercise 49 of Learn Ruby the Hard Way

The exercise asks to write a unit test for each function provided. One of the items I am testing is if a proper exception is raised. It is suggested that we use assert_raise for this purpose.

Here is the code I am testing:

class ParserError < Exception

end

Pair = Struct.new(:token, :word)

def peek(word_list)
    begin
        word_list.first.token
    rescue
        nil
    end 
end

def match(word_list, expecting)
    word = word_list.shift
    if word.token == expecting
        word
    else
        nil
    end
end

def skip_word(word_list, token)
    while peek(word_list) == token
        match(word_list, token)
    end
end

def parse_verb(word_list)
    skip_word(word_list, :stop)

    if peek(word_list) == :verb
        return match(word_list, :verb)
    else
        raise ParserError.new("Expected a verb next.")
    end
end

And here is the test, for the function parse_verb:

def test_parse_verb
    list_one = [Pair.new(:verb, 'go'), Pair.new(:noun, 'king')]
    assert_equal(parse_verb(list_one), Pair.new(:verb, 'go'))

    list_two = [Pair.new(:noun, 'player') ,Pair.new(:verb, 'go'), Pair.new(:noun, 'king')]
    assert_raise(ParserError.new("Expected a verb next.")) {parse_verb(list_two)}
end

When I run the test, it fails and here is the message I get:

Larson-2:test larson$ ruby test_sentence.rb
Loaded suite test_sentence
Started
.F..
Finished in 0.001204 seconds.

  1) Failure:
test_parse_verb(SentenceTests) [test_sentence.rb:36]:
[#<ParserError: Expected a noun or direction next.>] exception expected, not
Class: <ParserError>
Message: <"Expected a verb next.">
---Backtrace---
/Users/larson/Ruby/projects/ex48/lib/sentence.rb:45:in `parse_verb'
test_sentence.rb:36:in `block in test_parse_verb'
---------------

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

Test run options: --seed 40627

Based on my understanding of the assert_raise function, this test should pass, is there something wrong with the way I am using it?

If anybody would like a full source code of all the files I am working with I it is available here

Oahu answered 4/9, 2011 at 0:6 Comment(0)
B
34

assert_raise expects one or more exception classes as its parameters, rather than an instance of the required exception.

It also returns the exception raised so if you want to assert the message (or any other properties) you can do that separately. So try replacing:

assert_raise(ParserError.new("Expected a verb next.")) {parse_verb(list_two)}

with:

exception = assert_raise(ParserError) {parse_verb(list_two)}
assert_equal("Expected a noun or direction next.", exception.message) 
Buddle answered 4/9, 2011 at 10:12 Comment(1)
like @Felipe Almeida mentioned, from ruby 2.0.0 onwards the API for assert_raise has changed. The executing bloc now needs to be surrounded with do ... end for it to work. See the docs here: ruby-doc.org/stdlib-2.0.0/libdoc/test/unit/rdoc/Test/Unit/…Neoptolemus
F
2

For some reason, the answer given above didn't work for me (i'm using Ruby 2.0.0).

I has to wrap the Error class name in a String for it to work:

assert_raise("RuntimeError") { 
    # some code to trigger the error
}
Franctireur answered 2/10, 2013 at 2:36 Comment(2)
For me assert_raise("FooFoo"){ ... } always passes, no matter the value of the stringNortherner
@bottlenecked, rather string value is ignored and any exception is accepted. But if there is no exception the assertion fails. Still using a string is incorrect as you point out.Pants

© 2022 - 2024 — McMap. All rights reserved.