Python unittest - opposite of assertRaises?

前端 未结 10 661
甜味超标
甜味超标 2020-12-04 05:36

I want to write a test to establish that an Exception is not raised in a given circumstance.

It\'s straightforward to test if an Exception is raise

10条回答
  •  北海茫月
    2020-12-04 05:49

    You can define assertNotRaises by reusing about 90% of the original implementation of assertRaises in the unittest module. With this approach, you end up with an assertNotRaises method that, aside from its reversed failure condition, behaves identically to assertRaises.

    TLDR and live demo

    It turns out to be surprisingly easy to add an assertNotRaises method to unittest.TestCase (it took me about 4 times as long to write this answer as it did the code). Here's a live demo of the assertNotRaises method in action. Just like assertRaises, you can either pass a callable and args to assertNotRaises, or you can use it in a with statement. The live demo includes a test cases that demonstrates that assertNotRaises works as intended.

    Details

    The implementation of assertRaises in unittest is fairly complicated, but with a little bit of clever subclassing you can override and reverse its failure condition.

    assertRaises is a short method that basically just creates an instance of the unittest.case._AssertRaisesContext class and returns it (see its definition in the unittest.case module). You can define your own _AssertNotRaisesContext class by subclassing _AssertRaisesContext and overriding its __exit__ method:

    import traceback
    from unittest.case import _AssertRaisesContext
    
    class _AssertNotRaisesContext(_AssertRaisesContext):
        def __exit__(self, exc_type, exc_value, tb):
            if exc_type is not None:
                self.exception = exc_value.with_traceback(None)
    
                try:
                    exc_name = self.expected.__name__
                except AttributeError:
                    exc_name = str(self.expected)
    
                if self.obj_name:
                    self._raiseFailure("{} raised by {}".format(exc_name,
                        self.obj_name))
                else:
                    self._raiseFailure("{} raised".format(exc_name))
    
            else:
                traceback.clear_frames(tb)
    
            return True
    

    Normally you define test case classes by having them inherit from TestCase. If you instead inherit from a subclass MyTestCase:

    class MyTestCase(unittest.TestCase):
        def assertNotRaises(self, expected_exception, *args, **kwargs):
            context = _AssertNotRaisesContext(expected_exception, self)
            try:
                return context.handle('assertNotRaises', args, kwargs)
            finally:
                context = None
    

    all of your test cases will now have the assertNotRaises method available to them.

提交回复
热议问题