我正在尝试编写一个单元测试来执行写入stdout的函数,捕获该输出并检查结果。有问题的功能是一个黑盒子:我们无法改变它写出输出的方式。出于这个例子的目的,我已经对它进行了相当简化,但实际上该函数使用subprocess.call()生成了它的输出。
无论我尝试什么,我都无法捕获输出。它始终写入屏幕,测试失败,因为它没有捕获任何内容。我尝试了print()和os.system()。使用print(),我可以捕获stdout,但不能使用os.system()。
它也不是特定于单元测试。我没有用同样的结果编写了我的测试示例。
类似的问题已经被问了很多,而答案似乎都归结为使用subprocess.Popen()和communic(),但这需要更改黑盒子。我确定我找不到答案,但我很难过。
我们正在使用Python-2.7。
无论如何,我的示例代码是:
#!/usr/bin/env python
from __future__ import print_function
import sys
sys.dont_write_bytecode = True
import os
import unittest
import subprocess
from contextlib import contextmanager
from cStringIO import StringIO
# from somwhere import my_function
def my_function(arg):
#print('my_function:', arg)
subprocess.call(['/bin/echo', 'my_function: ', arg], shell=False)
#os.system('echo my_function: ' + arg)
@contextmanager
def redirect_cm(new_stdout):
old_stdout = sys.stdout
sys.stdout = new_stdout
try:
yield
finally:
sys.stdout = old_stdout
class Test_something(unittest.TestCase):
def test(self):
fptr = StringIO()
with redirect_cm(fptr):
my_function("some_value")
self.assertEqual("my_function: some_value\n", fptr.getvalue())
if __name__ == '__main__':
unittest.main()
答案 0 :(得分:4)
上述代码中有两个问题
StringIO fptr
未被当前和衍生进程共享,即使生成的进程已将结果写入StringIO
对象
os.popen()
,os.system()
或os模块中的exec*()
系列函数执行的 Changing sys.stdout
doesn’t affect the standard I/O streams个进程
一个简单的解决方案是
使用os.pipe
在两个进程之间共享结果
使用os.dup2
而不是更改sys.stdout
如下所示的演示示例
import sys
import os
import subprocess
from contextlib import contextmanager
@contextmanager
def redirect_stdout(new_out):
old_stdout = os.dup(1)
try:
os.dup2(new_out, sys.stdout.fileno())
yield
finally:
os.dup2(old_stdout, 1)
def test():
reader, writer = os.pipe()
with redirect_stdout(writer):
subprocess.call(['/bin/echo', 'something happened what'], shell=False)
print os.read(reader, 1024)
test()