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
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)