Take the 2-minute tour ×

I have a test module in the standard unittest format

class my_test(unittest.TestCase):

    def test_1(self):

    def test_2(self):

My company has a proprietary test harness that will execute my module as a command line script, and which will catch any errors raised by my module, but requires that my module be mute if successful.

So, I am trying to find a way to run my test module naked, so that if all my tests pass then nothing is printed to the screen, and if a test fails with an AssertionError, that error gets piped through the standard Python error stack (just like any other error would in a normal Python script.)

The docs advocate using the unittest.main() function to run all the tests in a given module like

if __name__ == "__main__":

The problem is that this wraps the test results in unittest's harness, so that even if all tests are successful, it still prints some fluff to the screen, and if there is an error, it's not simply dumped as a usual python error, but also dressed in the harness.

I've tried redirecting the output to an alternate stream using

with open('.LOG','a') as logf:
    suite = unittest.TestLoader().loadTestsFromTestCase(my_test)
    unittest.TextTestRunner(stream = logf).run(suite)

The problem here is that EVERYTHING gets piped to the log file (including all notice of errors). So when my companies harness runs the module, it complete's successfully because, as far as it can tell, no errors were raised (because they were all piped to the log file).

Any suggestions on how I can construct a test runner that suppresses all the fluff, and pipes errors through the normal Python error stack? As always, if you think there is a better way to approach this problem, please let me know.


Here is what I ended up using to resolve this. First, I added a "get_test_names()" method to my test class:

class my_test(unittest.TestCase):
    def get_test_names():
        """Return the names of all the test methods for this class."""
        test_names = [ member[0] for memeber in inspect.getmembers(my_test)
                       if 'test_' in member[0] ]

Then I replaced my call to unittest.main() with the following:

# Unittest catches all errors raised by the test cases, and returns them as 
# formatted strings inside a TestResult object. In order for the test 
# harness to catch these errors they need to be re-raised, and so I am defining 
# this CompareError class to do that. 
# For each code error, a CompareError will be raised, with the original error 
# stack as the argument. For test failures (i.e. assertion errors) an 
# AssertionError is raised.
class CompareError(Exception):
    def __init__(self,err):
        self.err = err
    def __str__(self):
        return repr(self.err)

# Collect all tests into a TestSuite()
all_tests = ut.TestSuite()
for test in my_test.get_test_names():
# Define a TestResult object and run tests
results = ut.TestResult()
# Re-raise any script errors
for error in results.errors:
    raise CompareError(error[1])
# Re-raise any test failures 
for failure in results.failures:
    raise AssertionError(failure[1])
share|improve this question
add comment

1 Answer

I came up with this. If you are able to change the command line you might remove the internal io redirection.

import sys, inspect, traceback

# redirect stdout,
# can be replaced by testharness.py > /dev/null at console
class devnull():
    def write(self, data):

f = devnull()
orig_stdout = sys.stdout
sys.stdout = f

class TestCase():
    def test_1(self):
        print 'test_1'

    def test_2(self):
        raise AssertionError, 'test_2'

    def test_3(self):
        print 'test_3'

if __name__ == "__main__":
    testcase = TestCase()
    testnames =  [ t[0] for t in inspect.getmembers(TestCase)
                        if t[0].startswith('test_') ]

    for testname in testnames:
            getattr(testcase, testname)()
        except AssertionError, e:
            print >> sys.stderr, traceback.format_exc()

# restore
sys.stdout = orig_stdout
share|improve this answer
A much belated thank you Gringo Suave. I ended up building a test runner using the TestSuite and TestResult classes, but I did lift the inspect.getmembers() call from your code. –  jeremiahbuddha Nov 7 '11 at 22:17
add comment

Your Answer


