如何在变量中捕获单元测试的stdout/stderr?
How to capture the stdout/stderr of a unittest in a variable?
如何在变量中捕获单元测试的stdout/stderr?我需要捕获以下单元测试的整个输出输出并将其发送到 SQS。我试过这个:
import unittest, io
from contextlib import redirect_stdout, redirect_stderr
class LogProcessorTests(unittest.TestCase):
def setUp(self):
self.var = 'this value'
def test_var_value(self):
with io.StringIO() as buf, redirect_stderr(buf):
print('Running LogProcessor tests...')
print('Inside test_var_value')
self.assertEqual(self.var, 'that value')
print('-----------------------')
print(buf.getvalue())
但是,它不起作用,以下输出仅出现在stdout/stderr。
Testing started at 20:32 ...
/Users/myuser/Documents/virtualenvs/app-venv3/bin/python3 "/Applications/PyCharm CE.app/Contents/helpers/pycharm/_jb_unittest_runner.py" --path /Users/myuser/Documents/projects/application/LogProcessor/tests/test_processor_tests.py
Launching unittests with arguments python -m unittest /Users/myuser/Documents/projects/application/LogProcessor/tests/test_processor_tests.py in /Users/myuser/Documents/projects/application/LogProcessor/tests
Running LogProcessor tests...
Inside test_var_value
that value != this value
Expected :this value
Actual :that value
<Click to see difference>
Traceback (most recent call last):
File "/Applications/PyCharm CE.app/Contents/helpers/pycharm/teamcity/diff_tools.py", line 32, in _patched_equals
old(self, first, second, msg)
File "/usr/local/Cellar/python/3.7.3/Frameworks/Python.framework/Versions/3.7/lib/python3.7/unittest/case.py", line 839, in assertEqual
assertion_func(first, second, msg=msg)
File "/usr/local/Cellar/python/3.7.3/Frameworks/Python.framework/Versions/3.7/lib/python3.7/unittest/case.py", line 1220, in assertMultiLineEqual
self.fail(self._formatMessage(msg, standardMsg))
File "/usr/local/Cellar/python/3.7.3/Frameworks/Python.framework/Versions/3.7/lib/python3.7/unittest/case.py", line 680, in fail
raise self.failureException(msg)
AssertionError: 'this value' != 'that value'
- this value
? ^^
+ that value
? ^^
During handling of the above exception, another exception occurred:
Traceback (most recent call last):
File "/usr/local/Cellar/python/3.7.3/Frameworks/Python.framework/Versions/3.7/lib/python3.7/unittest/case.py", line 59, in testPartExecutor
yield
File "/usr/local/Cellar/python/3.7.3/Frameworks/Python.framework/Versions/3.7/lib/python3.7/unittest/case.py", line 615, in run
testMethod()
File "/Users/myuser/Documents/projects/application/LogProcessor/tests/test_processor_tests.py", line 15, in test_var_value
self.assertEqual(self.var, 'that value')
Ran 1 test in 0.004s
FAILED (failures=1)
Process finished with exit code 1
Assertion failed
Assertion failed
有什么想法吗?如果需要更多信息,请告诉我。
老实说,最简单的方法可能是将您的输出重定向到 OS 级别--运行 从命令行进行测试并将其 > 输出到文件。
如果您使用构建系统来执行这些操作,那么构建系统应该会为您捕获输出,您可以从它的构建工件中提取输出。
如果您手动实例化测试运行程序(例如 unittest.TextTestRunner
),您可以指定它写入的(文件)流。默认情况下,这是 sys.stderr
,但您可以改用 StringIO。这将捕获单元测试本身的输出。您自己的 print-statements 的输出将不会被捕获,但您可以使用 redirect_stdout
上下文管理器,使用相同的 StringIO 对象。
请注意,我建议避免使用 print-statements,因为它们会干扰 unittest 框架的输出(您的测试输出会打断 unittest 框架的输出行)并且有点hack 重定向 stdout/stderr 流。更好的解决方案是改用 logging
模块。然后您可以添加一个日志记录处理程序,将所有日志消息写入 StringIO 以进行进一步处理(在您的情况下:发送到 SQS)。
下面是基于您使用 print-statements 的代码的示例代码。
#!/usr/bin/env python3
import contextlib
import io
import unittest
class LogProcessorTests(unittest.TestCase):
def setUp(self):
self.var = 'this value'
def test_var_value(self):
print('Running LogProcessor tests...')
print('Inside test_var_value')
self.assertEqual(self.var, 'that value')
print('-----------------------')
if __name__ == '__main__':
# find all tests in this module
import __main__
suite = unittest.TestLoader().loadTestsFromModule(__main__)
with io.StringIO() as buf:
# run the tests
with contextlib.redirect_stdout(buf):
unittest.TextTestRunner(stream=buf).run(suite)
# process (in this case: print) the results
print('*** CAPTURED TEXT***:\n%s' % buf.getvalue())
这会打印:
*** CAPTURED TEXT***:
Running LogProcessor tests...
Inside test_var_value
F
======================================================================
FAIL: test_var_value (__main__.LogProcessorTests)
----------------------------------------------------------------------
Traceback (most recent call last):
File "test.py", line 16, in test_var_value
self.assertEqual(self.var, 'that value')
AssertionError: 'this value' != 'that value'
- this value
? ^^
+ that value
? ^^
----------------------------------------------------------------------
Ran 1 test in 0.000s
FAILED (failures=1)
这证实了所有输出(来自单元测试框架和测试用例本身)都被捕获到 StringIO 对象中。
根据 contextlib.redirect_stdout 文档,这就是重定向 stderr
或 stdout
:
的方式
import io
import contextlib
f = io.StringIO()
with contextlib.redirect_stderr(f):
parser = target.parse_args([])
self.assertTrue("error: one of the arguments -p/--propagate -cu/--cleanup is required" in f.getvalue())
您还可以将其与另一个上下文管理器(如 assertRaises
)结合使用,如下所示:
f = io.StringIO()
with self.assertRaises(SystemExit) as cm, contextlib.redirect_stderr(f):
parser = target.parse_args([])
self.assertEqual(cm.exception.code, 2)
self.assertTrue("error: one of the arguments -p/--propagate -cu/--cleanup is required" in f.getvalue())
如何在变量中捕获单元测试的stdout/stderr?我需要捕获以下单元测试的整个输出输出并将其发送到 SQS。我试过这个:
import unittest, io
from contextlib import redirect_stdout, redirect_stderr
class LogProcessorTests(unittest.TestCase):
def setUp(self):
self.var = 'this value'
def test_var_value(self):
with io.StringIO() as buf, redirect_stderr(buf):
print('Running LogProcessor tests...')
print('Inside test_var_value')
self.assertEqual(self.var, 'that value')
print('-----------------------')
print(buf.getvalue())
但是,它不起作用,以下输出仅出现在stdout/stderr。
Testing started at 20:32 ...
/Users/myuser/Documents/virtualenvs/app-venv3/bin/python3 "/Applications/PyCharm CE.app/Contents/helpers/pycharm/_jb_unittest_runner.py" --path /Users/myuser/Documents/projects/application/LogProcessor/tests/test_processor_tests.py
Launching unittests with arguments python -m unittest /Users/myuser/Documents/projects/application/LogProcessor/tests/test_processor_tests.py in /Users/myuser/Documents/projects/application/LogProcessor/tests
Running LogProcessor tests...
Inside test_var_value
that value != this value
Expected :this value
Actual :that value
<Click to see difference>
Traceback (most recent call last):
File "/Applications/PyCharm CE.app/Contents/helpers/pycharm/teamcity/diff_tools.py", line 32, in _patched_equals
old(self, first, second, msg)
File "/usr/local/Cellar/python/3.7.3/Frameworks/Python.framework/Versions/3.7/lib/python3.7/unittest/case.py", line 839, in assertEqual
assertion_func(first, second, msg=msg)
File "/usr/local/Cellar/python/3.7.3/Frameworks/Python.framework/Versions/3.7/lib/python3.7/unittest/case.py", line 1220, in assertMultiLineEqual
self.fail(self._formatMessage(msg, standardMsg))
File "/usr/local/Cellar/python/3.7.3/Frameworks/Python.framework/Versions/3.7/lib/python3.7/unittest/case.py", line 680, in fail
raise self.failureException(msg)
AssertionError: 'this value' != 'that value'
- this value
? ^^
+ that value
? ^^
During handling of the above exception, another exception occurred:
Traceback (most recent call last):
File "/usr/local/Cellar/python/3.7.3/Frameworks/Python.framework/Versions/3.7/lib/python3.7/unittest/case.py", line 59, in testPartExecutor
yield
File "/usr/local/Cellar/python/3.7.3/Frameworks/Python.framework/Versions/3.7/lib/python3.7/unittest/case.py", line 615, in run
testMethod()
File "/Users/myuser/Documents/projects/application/LogProcessor/tests/test_processor_tests.py", line 15, in test_var_value
self.assertEqual(self.var, 'that value')
Ran 1 test in 0.004s
FAILED (failures=1)
Process finished with exit code 1
Assertion failed
Assertion failed
有什么想法吗?如果需要更多信息,请告诉我。
老实说,最简单的方法可能是将您的输出重定向到 OS 级别--运行 从命令行进行测试并将其 > 输出到文件。
如果您使用构建系统来执行这些操作,那么构建系统应该会为您捕获输出,您可以从它的构建工件中提取输出。
如果您手动实例化测试运行程序(例如 unittest.TextTestRunner
),您可以指定它写入的(文件)流。默认情况下,这是 sys.stderr
,但您可以改用 StringIO。这将捕获单元测试本身的输出。您自己的 print-statements 的输出将不会被捕获,但您可以使用 redirect_stdout
上下文管理器,使用相同的 StringIO 对象。
请注意,我建议避免使用 print-statements,因为它们会干扰 unittest 框架的输出(您的测试输出会打断 unittest 框架的输出行)并且有点hack 重定向 stdout/stderr 流。更好的解决方案是改用 logging
模块。然后您可以添加一个日志记录处理程序,将所有日志消息写入 StringIO 以进行进一步处理(在您的情况下:发送到 SQS)。
下面是基于您使用 print-statements 的代码的示例代码。
#!/usr/bin/env python3
import contextlib
import io
import unittest
class LogProcessorTests(unittest.TestCase):
def setUp(self):
self.var = 'this value'
def test_var_value(self):
print('Running LogProcessor tests...')
print('Inside test_var_value')
self.assertEqual(self.var, 'that value')
print('-----------------------')
if __name__ == '__main__':
# find all tests in this module
import __main__
suite = unittest.TestLoader().loadTestsFromModule(__main__)
with io.StringIO() as buf:
# run the tests
with contextlib.redirect_stdout(buf):
unittest.TextTestRunner(stream=buf).run(suite)
# process (in this case: print) the results
print('*** CAPTURED TEXT***:\n%s' % buf.getvalue())
这会打印:
*** CAPTURED TEXT***:
Running LogProcessor tests...
Inside test_var_value
F
======================================================================
FAIL: test_var_value (__main__.LogProcessorTests)
----------------------------------------------------------------------
Traceback (most recent call last):
File "test.py", line 16, in test_var_value
self.assertEqual(self.var, 'that value')
AssertionError: 'this value' != 'that value'
- this value
? ^^
+ that value
? ^^
----------------------------------------------------------------------
Ran 1 test in 0.000s
FAILED (failures=1)
这证实了所有输出(来自单元测试框架和测试用例本身)都被捕获到 StringIO 对象中。
根据 contextlib.redirect_stdout 文档,这就是重定向 stderr
或 stdout
:
import io
import contextlib
f = io.StringIO()
with contextlib.redirect_stderr(f):
parser = target.parse_args([])
self.assertTrue("error: one of the arguments -p/--propagate -cu/--cleanup is required" in f.getvalue())
您还可以将其与另一个上下文管理器(如 assertRaises
)结合使用,如下所示:
f = io.StringIO()
with self.assertRaises(SystemExit) as cm, contextlib.redirect_stderr(f):
parser = target.parse_args([])
self.assertEqual(cm.exception.code, 2)
self.assertTrue("error: one of the arguments -p/--propagate -cu/--cleanup is required" in f.getvalue())