Reputation:
I'm practicing TDD in Python and came across a problem in testing whether an exception is raised.
Here is my test_phonebook.py
with test_add_empty_name_raises_exception
which fails.
import unittest
import phonebook
class Test(unittest.TestCase):
def test_add_empty_name_raises_exception(self):
self.assertRaises(ValueError, phonebook.add, "", "1111111111")
if __name__ == "__main__":
# import sys;sys.argv = ['', 'Test.testName']
unittest.main()
Below is my phonebook.py
with the method add
which adds the data into the dictionary.
import re
_phonebook = {}
file_name = "phonebook.txt"
def is_valid_name(name):
return re.search(r"([A-Z][a-z]*)([\\s\\\'-][A-Z][a-z]*)*", name) is not None
def is_valid_number(number):
return re.search(r"\+?[\d ]+$", number) is not None
def add(name, number):
try:
if is_valid_name(name) and is_valid_number(number):
_phonebook[name] = number
else:
raise ValueError("Invalid arguments.", name, number)
except ValueError as err:
print err.args
if __name__ == '__main__':
pass
My problem is that the test fails even though it is seen in the console log that there was a ValueError
raised within the add
method.
Finding files... done.
Importing test modules ... done.
('Invalid arguments.', '', '1111111111')
======================================================================
FAIL: test_add_empty_name_raises_exception (path.to.phonebook.test_phonebook.Test)
----------------------------------------------------------------------
Traceback (most recent call last):
File "path\to\phonebook\test_phonebook.py", line 13, in test_add_empty_name_raises_exception
self.assertRaises(ValueError, phonebook.add, "", "1111111111")
AssertionError: ValueError not raised
----------------------------------------------------------------------
Ran 1 test in 0.002s
How do I solve this? I there something I forgot?
I also tried using the new format for handling exceptions in tests in Python 2.7 but it still hasn't caught the ValueError
raising.
def test_add_empty_name_raises_exception(self):
with self.assertRaises(ValueError):
self.phonebook.add("", "1111111111)
I also changed the form of the test case into using lambdas but still no changes.
def test_add_empty_name_raises_exception(self):
self.assertRaises(ValueError, lambda: phonebook.add("", "1111111111"))
I also cleaned my directory and restarted Eclipse Luna and problem still persists.
Possible solution
I was reading the 8.Errors and Exceptions documentation and got to the "Raising Exceptions" part which states that:
If you need to determine whether an exception was raised but don’t intend to handle it,
a simpler form of the raise statement allows you to re-raise the exception:
I added this to the existing add
method as such:
def add(name, number):
try:
if is_valid_name(name) and is_valid_number(number):
_phonebook[name] = number
print "Added %s:\t%s" % (name, number)
else:
raise ValueError("Invalid arguments.", name, number)
except ValueError as err:
print err.args
raise
Which caused the test case to pass.
Is this the correct way? To call raise
again in the except
block?
Upvotes: 0
Views: 2240
Reputation: 3956
When you catch an exception (in your except ValueError as err:
block), you prevent it from continuing back up the call stack to eventually terminate the program. Essentially, you're saying "I know how to handle this, so no need to panic anyone else."
Re-raising an exception is the proper thing to do if you caught the exception but didn't do so to actually fix anything, for instance, to log that it occurred. Typically, though, one catches an exception in order to correct it.
In your case, you're catching the exception almost immediately after you yourself raised it. Why not put your logging statement in the same else
block as the raise
? No need for a try: ... except:
indent at all.
def add(name, number):
if is_valid_name(name) and is_valid_number(number):
_phonebook[name] = number
print "Added %s:\t%s" % (name, number)
else:
print "Invalid arguments.", name, number
raise ValueError("Invalid arguments.", name, number)
return
Upvotes: 2