I am trying to do something similarly 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 different work according to different test case class, you can achieve it like this:
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)