6

I've got code where assertRaises throws an exception when assertRaises fails. I thought that if assertRaises fails then the test would fail and I'd get a report at the end that says the test failed. I wasn't expecting the exception to be thrown. Below is my code. I'm I doing something wrong? I'm using Python 2.6.2.

import unittest

class myClass:

    def getName(self):

        raise myExcOne, "my exception one"
        #raise myExcTwo, "my exception two"
        #return "a"

class myExcOne(Exception):
    "exception one"

class myExcTwo(Exception):
    "exception two"


class test_myClass(unittest.TestCase):

    def setUp(self):

        self.myClass = myClass()

    def testgetNameEmpty(self):
        #self.assertRaises(myExcOne,self.myClass.getName)
        #self.assertRaises(myExcTwo,self.myClass.getName)

        try:
            self.assertRaises(myExcTwo,self.myClass.getName)
        except Exception as e:
            pass

if __name__ == "__main__":

    #unittest.main()

    suite = unittest.TestLoader().loadTestsFromTestCase(test_myClass)
    unittest.TextTestRunner(verbosity=2).run(suite)
pjama
  • 3,014
  • 3
  • 26
  • 27
  • what do you specifically mean by 'assert fails'? Can you post a stacktrace or an error message? – Mark Roddy Aug 04 '09 at 23:59
  • I re-read the doc and throwing an exception when assertRaises fails is the expected behavior. I misunderstood how the tool works. I forgot to mention this in the previous post. If I catch the exception, the report tells me that the test passed even though it didn't. I've updated my code on –  Aug 05 '09 at 00:45

2 Answers2

6

The code as posted is wrong. For a start, class myClass(): shoudl be class myClass:. Also if name == "main": should be:

if __name__ == "__main__":
    unittest.main()

Apart from these problems, this fails because getName() is raising exception myExcOne and your test expects exception myExcTwo.

Here is some code that works. Please edit the code in your question so that it is easy for us to cut and paste it into a Python session:

import unittest

class myExcOne(Exception): "exception one"

class myExcTwo(Exception): "exception two"

class myClass:
    def getName(self):
        raise myExcTwo

class test_myClass(unittest.TestCase):
    def setUp(self):
        self.myClass = myClass()
    def testgetNameEmpty(self):
        #self.assertRaises(myExcOne,self.myClass.getName)
        self.assertRaises(myExcTwo,self.myClass.getName)

if __name__ == "__main__":
    unittest.main()
mhawke
  • 84,695
  • 9
  • 117
  • 138
  • Hi mhawke, The __main__ got messed up in the copy and paste process. For the myClass(), the original class inherited so I forgot to delete the () when I made the small testcase. The test is supposed to fail. I'm trying to understand how the tool behaves when an assert fails. For my original post, I misunderstood that the tool is supposed to throw an exception if an assert fails. I've updated the code to catch the exception and do nothing with it. Even though the assert fails, the report says it passed. Brian –  Aug 05 '09 at 00:58
6

Starting with an aside, the () after the classname in a class statement is perfectly correct in modern Python -- not an error at all.

On the meat of the issue, assertRaises(MyException, foo) is documented to propagate exceptions raised by calling foo() whose type is NOT a subclass of MyException -- it only catches MyException and subclasses thereof. As your code raises an exception of one type and your test expects one of a different unrelated type, the raised exception will then propagate, as per the docs of the unittest module, here, and I quote:

The test passes if exception is raised, is an error if another exception is raised, or fails if no exception is raised.

And "is an error" means "propagates the other exception".

As you catch the exception propagating in your try/except block, you nullify the error, and there's nothing left for unittest to diagnose. If your purpose is to turn this error into a failure (a debatable strategy...), your except block should call self.fail.

code_dredd
  • 5,915
  • 1
  • 25
  • 53
Alex Martelli
  • 854,459
  • 170
  • 1,222
  • 1,395
  • Thank you for your help!!! I didn't catch my misunderstanding of unittest till after I posted. With the code above if I run it I get the message . I'd expect it to fail but understand why it gives the message. When I added self.fail in the except block it throws another exception. Any suggestions to allow all tests to run and report the errors at the end? I found but I'm not sure how (or if I can) get to the results. –  Aug 05 '09 at 20:59
  • all the testmethods DO run and report errors (E) and failures (F) [which are diagnosed by special exceptions, actually] with the normal unit-test runner (unittest.main) -- I'm surprised to hear that TextTestRunner behaves differently for you, as this is exactly what unittest.main uses (via the unittest.TestProgram class), check the sources... you DO get the expected results w/unittest.main, right? – Alex Martelli Aug 05 '09 at 21:38
  • If I take out the try/except block and uncomment then it is my debugger that is stopping the execution. I ran the program from a command line it ran all the tests and gave the results I expect. This is what I was looking for. But if I ran the code as it is listed above it tells me it passes even though it should fail. I'm not worried about this since running the unit test from the command line gives me what I want. Thank you again for your help. –  Aug 07 '09 at 14:40
  • Your debugger is apparently being over-eager in prematurely catching exceptions that are going to be handled just fine "upstream". Check how to configure your debugger to NOT do that!-) And no, the way you code it above it should NOT fail in any way, shape or form, as I explained: you're DELIBERATELY forcing it to succeed by catching and ignoring the exception. – Alex Martelli Aug 07 '09 at 16:11