The short answer is verbosity, runner = unittest.TextTestRunner(verbosity=2)
.
The longer answer, if you want to store the output streams is more complicated.
std.io
and std.err
are managed by the OS and they are flushed differently when connected to the terminal than when redirected to a file.
Some examples,
Unit under test (filename testablepython.py
)
def run():
print(f"{__name__} unit print")
return(True)
test code body (filename test/test_tests.py
)
import unittest
import logging
import testablepython as unit
import os
import sys
# import pandas as pd
class Test_ClassOne(unittest.TestCase):
def test_A(self):
self.assertTrue(unit.run())
logging.info('log: passed test_one'
def test_B(self):
self.assertFalse(not unit.run())
logging.info('log: passed test_falseisnottrue')
class Test_ClassTwo(unittest.TestCase):
def test_three(self):
logging.info(f"log: in test_three, does not call unit")
self.assertTrue(True)
the main block that works to console but not on redirect:
if __name__ == '__main__':
logging.basicConfig(level=logging.DEBUG)
runner = unittest.TextTestRunner(verbosity=2)
unittest.main(testRunner=runner)
console output:
$python -m test.test_tests
test_A (__main__.Test_ClassOne) ... testablepython unit print
INFO:root:log: passed test_one
ok
test_B (__main__.Test_ClassOne) ... testablepython unit print
INFO:root:log: passed test_falseisnottrue
ok
test_three (__main__.Test_ClassTwo) ... INFO:root:log: output three ['fred', 'alaska', 'baker']
ok
----------------------------------------------------------------------
Ran 3 tests in 0.003s
OK
$
Note the lack of a newline between the test fixture and the print()
code from the unit under test, no flush. On redirect the streams are un-mixed, std.err
first then std.io
.
$ python -m test.test_tests &> temp.txt
$ cat temp.txt
test_A (__main__.Test_ClassOne) ... INFO:root:log: passed test_one
ok
test_B (__main__.Test_ClassOne) ... INFO:root:log: passed test_falseisnottrue
ok
test_three (__main__.Test_ClassTwo) ... INFO:root:log: output three ['fred', 'alaska', 'baker']
ok
----------------------------------------------------------------------
Ran 3 tests in 0.001s
OK
testablepython unit print
testablepython unit print
The solution seems to be to reconfigure the outputs to force them to flush during operation.
solution:
if __name__ == '__main__':
logging.basicConfig(level=logging.DEBUG)
sys.stdout = os.fdopen(sys.stdout.fileno(), 'w', 1)
sys.stderr = os.fdopen(sys.stderr.fileno(), 'w', 1)
runner = unittest.TextTestRunner( verbosity=2)
unittest.main(testRunner=runner)
Note the lack of a newline between the test fixture and the print()
code from the unit under tesNow we get the desired redirected output:
$ python -m test.test_tests &> temp.txt
$ cat temp.txt
test_A (__main__.Test_ClassOne) ... testablepython unit print
INFO:root:log: passed test_one
ok
test_B (__main__.Test_ClassOne) ... testablepython unit print
INFO:root:log: passed test_falseisnottrue
ok
test_three (__main__.Test_ClassTwo) ... INFO:root:log: output three ['fred', 'alaska', 'baker']
ok
----------------------------------------------------------------------
Ran 3 tests in 0.002s
Or we can see both by calling unittest with a tee: python -m test.test_tests 2>&1 | tee tmp.txt