Python unittest, do something only if the test fails

When using the unittest library from python 3, I would like to do some action only if the test failed (but it should be at the class level, so I don't need to write it for each test). For example, when using behave, there was something like:

 def after_step(context, step): if step.status == "failed": ... 

Is there something similar for unittest library, and if not, what is the easiest way to do something like this?

+8
python unit-testing
source share
4 answers

I am trying to do something like this recently and I found a way out:

 import unittest class MyTestResult(unittest.TestResult): def addFailure(self, test, err): # here you can do what you want to do when a test case fails print('test failed!') super(MyTestResult, self).addFailure(test, err) def addError(self, test, err): # here you can do what you want to do when a test case raises an error super(MyTestResult, self).addError(test, err) class MyUT(unittest.TestCase): def test_fail(self): self.assertEqual(1, 2, '123') self.assertTrue("ABc".isupper()) if __name__ == '__main__': unittest.main(testRunner=unittest.TextTestRunner(resultclass=MyTestResult)) 

If you want to do other work according to another class of test case, you can achieve this as follows:

 import unittest class MyUT(unittest.TestCase): class TestResult(unittest.TestResult): def addFailure(self, test, err): print('do something when test case failed') super(MyUT.TestResult, self).addFailure(test, err) def addError(self, test, err): print('test case error') super(MyUT.TestResult, self).addError(test, err) def test_fail(self): self.assertEqual(1, 2, "1=2") class MyUT2(unittest.TestCase): class TestResult(unittest.TestResult): def addFailure(self, test, err): print('do something else when test case failed') super(MyUT2.TestResult, self).addFailure(test, err) def addError(self, test, err): print('test case error') super(MyUT2.TestResult, self).addError(test, err) def test_fail(self): self.assertEqual(1, 2, "1=2") if __name__ == '__main__': classes = [MyUT, MyUT2] for c in classes: suite = unittest.TestLoader().loadTestsFromTestCase(c) unittest.TextTestRunner(resultclass=c.TestResult).run(suite) 
+4
source share

You can try to do this with a decorator:

 class ExceptionHandler(object): def __init__(self, f): self.f = f def __call__(self, *args, **kwargs): try: self.f(*args, **kwargs) except: print('do smth') 

And in unit test:

 @ExceptionHandler def test_fail(self): self.assert_false(True) 
+1
source share

You can to these cool things. Override the default exception handler to your custom one, which calls the original, and set your custom attributes:

 import sys import unittest has_failures = [] class IntegrationTests(unittest.TestCase): old_failureException = unittest.TestCase.failureException @property def failureException(self): has_failures.append('fail') return self.old_failureException def setUp(self): sys.stderr.write('Setup for %s\n' % self._testMethodName) if has_failures: self.skipTest("An test has failed, skipping everything else!") def test_thing1(self): self.assertEqual(1, 2) def test_thing2(self): pass def load_tests(loader, standard_tests, pattern): suite = unittest.TestSuite() suite.addTest( IntegrationTests( 'test_thing1' ) ) suite.addTest( IntegrationTests( 'test_thing2' ) ) return suite # Comment this to run individual Unit Tests load_tests = None if __name__ == "__main__": unittest.main(verbosity=3) 

Results:

 test_thing1 (__main__.IntegrationTests) ... Setup for test_thing1 FAIL test_thing2 (__main__.IntegrationTests) ... Setup for test_thing2 skipped 'An test has failed, skipping everything else!' ====================================================================== FAIL: test_thing1 (__main__.IntegrationTests) ---------------------------------------------------------------------- Traceback (most recent call last): File "D:\User\Downloads\text.py", line 27, in test_thing1 self.assertEqual(1, 2) AssertionError: 1 != 2 ---------------------------------------------------------------------- Ran 2 tests in 0.003s FAILED (failures=1, skipped=1) 

Recommendations:

  1. Getting Python Unit Test Results in the tearDown () Method
  2. if the condition in setUp () ignore the test
  3. How do you generate dynamic (parameterized) unit tests in Python?
  4. How to get the name of a running test suite from testsuite in unittest
0
source share

Using a private variable is not very good, but I have not found another way to access an object that tracks the test results.

 import unittest class TmpTest(unittest.TestCase): def tearDown(self): result = self._resultForDoCleanups if not result.wasSuccessful(): print "*** test failed" def testFoo(self): self.assertEqual(2, 2) if "__main__" == __name__: unittest.main() 
-one
source share

All Articles