Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Run Python unittest so that nothing is printed if successful, only AssertionError() if fails

I have a test module in the standard unittest format

class my_test(unittest.TestCase):

    def test_1(self):
        [tests]

    def test_2(self):
        [tests]
  etc....

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__":
    unittest.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.

EDIT:

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):
  etc....
    @staticmethod
    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():
    all_tests.addTest(my_test(test))
# Define a TestResult object and run tests
results = ut.TestResult()
all_tests.run(results)
# 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])
like image 506
jeremiahbuddha Avatar asked Aug 24 '11 19:08

jeremiahbuddha


People also ask

How do you assert none in Python?

assertIsNone() in Python is a unittest library function that is used in unit testing to check that input value is None or not. This function will take two parameters as input and return a boolean value depending upon assert condition. If input value is equal to None assertIsNone() will return true else return false.

What does Unittest main () do?

Internally, unittest. main() is using a few tricks to figure out the name of the module (source file) that contains the call to main() . It then imports this modules, examines it, gets a list of all classes and functions which could be tests (according the configuration) and then creates a test case for each of them.

How do I run a Unittest in Python?

If you're using the PyCharm IDE, you can run unittest or pytest by following these steps: In the Project tool window, select the tests directory. On the context menu, choose the run command for unittest . For example, choose Run 'Unittests in my Tests…'.

Which item in Python will stop a unit test abruptly?

An exception object is created when a Python script raises an exception. If the script explicitly doesn't handle the exception, the program will be forced to terminate abruptly.


1 Answers

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):
        pass

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:
        try:
            getattr(testcase, testname)()
        except AssertionError, e:
            print >> sys.stderr, traceback.format_exc()

# restore
sys.stdout = orig_stdout
like image 59
Gringo Suave Avatar answered Sep 19 '22 23:09

Gringo Suave