Can Python unittest automatically reattempt a failed testcase / suite?

The Python unittest module in intended for writing Python unit tests. ;-) It's not so well suited for other kinds of testing. The nose package is also a unit test framework.

I have written several testing frameworks in Python that are designed to test systems. The systems can be distributed, and automated with various interfaces. Two are open-source.

The Pycopia project is a collection of Python modules that runs on Linux. It is provided as a collection of namespace subpackages, one of which is the QA package that is a testing framework.

A subset-fork of this is named powerdroid, and it is intended to control instrumentation for taking physical measurements (such as voltage, current, etc.) via. RS-232, IEEE-488,etc. It provides an alternative Python interface to the linux-gpib project.

So you may start with these, rather than "reinvent the wheel", if you want. You may not have to throw away existing tests, since the framework can invoke any subprocess you can start existing tests with it. This also runs on Linux.


4 years after the original question - I hope that anyone would care :) Here's my solution for doing this on top of unittest. It's kind of ugly and relies on the implementation of the TestCase base class , but it works.

class MyTest(unittest.TestCase):
    ###
    ### Insert test methods here
    ###

    # Wrapping each test method so that a retry would take place.  
    def run(self, result=None):
        self.origTestMethodName = self._testMethodName
        self._testMethodName = "_testRetryWrapper"
        super(MyTest, self).run(result)
        self._testMethodName = self.origTestMethodName

    def _testRetryWrapper(self):
        testMethod = getattr(self, self.origTestMethodName)
        retryAttemptsLeft = settings.testRetryCount

        while True:
            try:
                testMethod()
                break
            except:
                if retryAttemptsLeft == 0:
                    raise
                else:
                    retryAttemptsLeft = retryAttemptsLeft - 1

I have improved Shlomi Király's answer slightly so that it doesn't violate with the unittest framework and skipping testcases still works:

class MyTest(unittest.TestCase):

#Eanble retries if specified in configuration file by attribute testRetryCount
def run(self, result=None):
    self.origTestMethodName = self._testMethodName
    retryAttemptsLeft = configuration.testRetryCount

    failuresBefore = len(result.failures) #check how many tests that are marked as failed before starting
    errorsBefore = len(result.errors) #check how many tests that are marked as failed before starting

    super(MyTest, self).run(result)
    if failuresBefore < len(result.failures): # If last test failed
        while True:
            if retryAttemptsLeft == 0:
                self.logger.error("Test failed after "+str(configuration.testRetryCount+1)+" attempts")
                break
            else:
                result.failures.pop(-1) #Removing last failure result
                self.logger.error("Test failed - retryAttemptsLeft: "+str(retryAttemptsLeft))
                retryAttemptsLeft = retryAttemptsLeft - 1

                super(MyTest, self).run(result)

    elif errorsBefore < len(result.errors): # If last test failed due to error
        while True:
            if retryAttemptsLeft == 0:
                self.logger.error("Test error after "+str(configuration.testRetryCount+1)+" attempts")
                break
            else:
                result.errors.pop(-1) #Removing last error result
                self.logger.error("Test error - retryAttemptsLeft: "+str(retryAttemptsLeft))
                retryAttemptsLeft = retryAttemptsLeft - 1

                super(MyTest, self).run(result)