Proper Assert_Raise Unit Testing and Use of Exception Class

Andrew Lauer Barinov picture Andrew Lauer Barinov · Sep 4, 2011 · Viewed 13.7k times · Source

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

Answer

Steve picture Steve · Sep 4, 2011

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)