Exception raising does not reflect in test case even though raised as seen in logs
Question: 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](https://docs.python.org/2/tutorial/errors.html) documentation and
got to the "[Raising
Exceptions](https://docs.python.org/2/tutorial/errors.html#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?


Answer: 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
    

