Cancel stdout / stderr of the program under test, but save unittest output

I have this sample code ( test_it.py ):

 import sys def give_me_5(): print >>sys.stdout, "STDOUT" print >>sys.stderr, "STDERR" return 6 import unittest class TestMe(unittest.TestCase): def setUp(self): pass def test_give_me_5(self): self.assertEqual(give_me_5(), 5) if __name__ == '__main__': unittest.main() 

Which gives me the following result:

 Β» python -m unittest test_it A long annoying output message A long annoying error message F ====================================================================== FAIL: test_give_me_5 (__main__.TestMe) ---------------------------------------------------------------------- Traceback (most recent call last): File "xx.py", line 17, in test_give_me_5 self.assertEqual(give_me_5(), 5) AssertionError: 6 != 5 ---------------------------------------------------------------------- Ran 1 test in 0.000s FAILED (failures=1) 

But because of the long, annoying messages created by the program under test (the real program produces LOTS of output), I can not see the unittest output. I would like to get rid of the stdout / stderr of the test function ( give_me_5 ), but I still want to see stdout / stderr from unittest . I would like to get this result:

 Β» python -m unittest test_it F ====================================================================== FAIL: test_give_me_5 (__main__.TestMe) ---------------------------------------------------------------------- Traceback (most recent call last): File "xx.py", line 17, in test_give_me_5 self.assertEqual(give_me_5(), 5) AssertionError: 6 != 5 ---------------------------------------------------------------------- Ran 1 test in 0.000s FAILED (failures=1) 

Thus, the result created by the program under test (both stdout and stderr) is filtered using unittest , but the output generated by unittest is saved . I do not want to change the tested code (without redirection in the code itself). I just want to tell unittest that all the output to stdout / stderr generated by the test code should be discarded.

Is it possible?

+5
source share
3 answers

@ Alik's suggestion was correct. But I think it can be improved.

 import sys # StringIO is replaced in Python 3: try: from StringIO import StringIO except ImportError: from io import StringIO class ReplaceStd(object): """ Let make it pythonic. """ def __init__(self): self.stdout = None self.stderr = None def __enter__(self): self.stdout = sys.stdout self.stderr = sys.stderr # as it was suggseted already: sys.stdout = StringIO() sys.stderr = StringIO() def __exit__(self, type, value, traceback): sys.stdout = self.stdout sys.stderr = self.stderr print('I am here') with ReplaceStd(): print('I am not') print('I am back') 

And the conclusion:

 I am here I am back 
+5
source

Temporarily replace sys.stdout and sys.stderr file instances. For example, you can use StringIO as memory buffers.

 from StringIO import StringIO ..... class TestMe(unittest.TestCase): def setUp(self): pass def test_give_me_5(self): stdout = sys.stdout stderr = sys.stderr sys.stdout = StringIO() sys.stderr = StringIO() self.assertEqual(give_me_5(), 5) sys.stdout = stdout sys.stderr = stderr 

You might want to add exception handling or even include this code in context manager to reuse it

+4
source

For reference (and for comments), here is the code I used (inspired by @Alik's answer):

 import sys def give_me_5(): print >>sys.stdout, "A long annoying output message" print >>sys.stderr, "A long annoying error message" return 6 import unittest def redirect(stdout_file=None, stderr_file=None): new_stdout = open(stdout_file, 'w') if stdout_file else None new_stderr = open(stderr_file, 'w') if stderr_file else None if new_stdout : sys.stdout = new_stdout if new_stderr : sys.stderr = new_stderr def redirect_testcase(test_case): logfile = '.'.join([test_case.__module__, test_case.__class__.__name__, 'out']) errfile = '.'.join([test_case.__module__, test_case.__class__.__name__, 'err']) redirect(logfile, errfile) class TestMe(unittest.TestCase): def setUp(self): redirect_testcase(self) def test_give_me_5(self): self.assertEqual(give_me_5(), 5) if __name__ == '__main__': unittest.main() 

Now just by doing redirect_testcase(self) , stdout / stderr will get a redirect to test_it.TestMe.out / test_it.TestMe.err , and the output of unittest will be visible in the stdout / stderr console (and can be redirected through the shell if necessary).

There was a problem (I still do not know how to fix it): all tests in a specific TestCase overwrite .out / .err . It would be nice to open a different out / log file for each test (as opposed to the usual for each TestCase)

0
source

All Articles