我正在尝试编写一个单元测试,该测试执行一个写入标准输出的函数,捕获该输出并检查结果。所讨论的函数是一个黑匣子:我们无法更改它写入输出的方式。出于本示例的目的,我对其进行了相当多的简化,但本质上该函数使用 subprocess.call() 生成其输出。
无论我尝试什么,我都无法捕获输出。它总是被写入屏幕,并且测试失败,因为它没有捕获任何内容。我尝试了 print() 和 os.system()。使用 print() 我可以捕获标准输出,但也不能使用 os.system() 。
它也不是特定于单元测试的。我已经编写了我的测试示例,但没有得到相同的结果。
类似的问题已经被问了很多,答案似乎都归结为使用 subprocess.Popen() 和 communications(),但这需要更改黑匣子。我确信有一个我还没有遇到的答案,但我很困惑。
我们使用的是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()
Run Code Online (Sandbox Code Playgroud)
上面的代码有两个问题
\n\nStringIO fptrStringIO不被当前进程和衍生进程共享,即使衍生进程已将结果写入对象,我们也无法在当前进程中获取结果
更改sys.stdoutos.popen()不会影响或os 模块中的函数系列os.system()执行的进程的标准 I/O 流exec*()
一个简单的解决方案是
\n\n用于os.pipe在两个进程之间共享结果
使用os.dup2而不是改变sys.stdout
演示示例如下所示
\n\nimport sys\nimport os\nimport subprocess\nfrom contextlib import contextmanager\n\n\n@contextmanager\ndef redirect_stdout(new_out):\n old_stdout = os.dup(1)\n try:\n os.dup2(new_out, sys.stdout.fileno())\n yield\n finally:\n os.dup2(old_stdout, 1)\n\n\ndef test():\n reader, writer = os.pipe()\n\n with redirect_stdout(writer):\n subprocess.call([\'/bin/echo\', \'something happened what\'], shell=False)\n\n print os.read(reader, 1024)\n\n\ntest()\nRun Code Online (Sandbox Code Playgroud)\n
| 归档时间: |
|
| 查看次数: |
2210 次 |
| 最近记录: |