无法使用单元测试捕获标准输出
Can't capture stdout with unittest
我有一个 python3.7 脚本,它将 YAML 文件作为输入并根据其中的说明对其进行处理。我用于单元测试的 YAML 文件如下所示:
...
tasks:
- echo '1'
- echo '2'
- echo '3'
- echo '4'
- echo '5'
脚本循环执行任务,然后使用 os.system()
调用运行每个任务。
手动测试表明,输出符合预期:
1
2
3
4
5
但是我不能让它在我的单元测试中工作。以下是我尝试捕获输出的方式:
from application import application
from io import StringIO
import unittest
from unittest.mock import patch
class TestApplication(unittest.TestCase):
def test_application_tasks(self):
expected = ['1','2','3','4','5']
with patch('sys.stdout', new=StringIO()) as fakeOutput:
application.parse_event('some event') # print() is called here within parse_event()
self.assertEqual(fakeOutput.getvalue().strip().split(), expected)
当运行python3 -m unittest discover -s tests
时,我得到的只是AssertionError: Lists differ: [] != ['1', '2', '3', '4', '5']
。
我也试过用with patch('sys.stdout', new_callable=StringIO) as fakeOutput:
代替,但没有用。
我尝试的另一件事是 self.assertEqual(fakeOutput.getvalue(), '1\n2\n3\n4\n5')
,这里是单元测试输出的内容:
AssertionError: '' != '1\n2\n3\n4\n5'
+ 1
+ 2
+ 3
+ 4
+ 5
显然,脚本可以运行并输出正确的结果,但是 fakeOutput
没有捕捉到它。
使用patch
作为装饰器也不起作用:
from application import application
from io import StringIO
import unittest
from unittest.mock import patch
class TestApplication(unittest.TestCase):
@patch('sys.stdout', new_callable=StringIO)
def test_application_tasks(self):
expected = ['1','2','3','4','5']
application.parse_event('some event') # print() is called here within parse_event()
self.assertEqual(fakeOutput.getvalue().strip().split(), expected)
会输出完全相同的错误:AssertionError: Lists differ: [] != ['1', '2', '3', '4', '5']
os.system
运行s 一个新进程。如果您使用 monkey-patch sys.stdout
这会影响当前进程,但不会对任何新进程产生影响。
考虑:
import sys
from os import system
from io import BytesIO
capture = sys.stdout = BytesIO()
system("echo Hello")
sys.stdout = sys.__stdout__
print(capture.getvalue())
没有捕获任何内容,因为只有子进程写入了它的标准输出。没有任何内容写入您的 Python 进程的标准输出。
通常,避免 os.system
。相反,使用 subprocess
模块,它可以让您从 运行.
的过程中捕获输出
谢谢你,让-保罗·卡尔德隆。我意识到 os.system()
创建了一个完全不同的过程,因此我需要以不同的方式解决问题,只有在我发布问题之后:)
为了真正能够测试我的代码,我不得不使用 subprocess
而不是 os.system()
重写它。最后,我使用 subprocess_run_result = subprocess.run(task, shell=True, stdout=subprocess.PIPE)
然后使用 subprocess_run_result.stdout.strip().decode("utf-8")
.
得到结果
在测试中,我只是创建了一个 class 的实例并调用了一个方法,该方法在子进程中运行任务。
我的整个重构代码和测试是here in this commit如果有人想看的话。
您的解决方案很好,只需使用 getvalue
代替,如下所示:
with patch("sys.stdout", new_callable=StringIO) as f:
print("Foo")
r = f.getvalue()
print("r: {r!r} ;".format(r=r))
r: "Foo" ;
我有一个 python3.7 脚本,它将 YAML 文件作为输入并根据其中的说明对其进行处理。我用于单元测试的 YAML 文件如下所示:
...
tasks:
- echo '1'
- echo '2'
- echo '3'
- echo '4'
- echo '5'
脚本循环执行任务,然后使用 os.system()
调用运行每个任务。
手动测试表明,输出符合预期:
1
2
3
4
5
但是我不能让它在我的单元测试中工作。以下是我尝试捕获输出的方式:
from application import application
from io import StringIO
import unittest
from unittest.mock import patch
class TestApplication(unittest.TestCase):
def test_application_tasks(self):
expected = ['1','2','3','4','5']
with patch('sys.stdout', new=StringIO()) as fakeOutput:
application.parse_event('some event') # print() is called here within parse_event()
self.assertEqual(fakeOutput.getvalue().strip().split(), expected)
当运行python3 -m unittest discover -s tests
时,我得到的只是AssertionError: Lists differ: [] != ['1', '2', '3', '4', '5']
。
我也试过用with patch('sys.stdout', new_callable=StringIO) as fakeOutput:
代替,但没有用。
我尝试的另一件事是 self.assertEqual(fakeOutput.getvalue(), '1\n2\n3\n4\n5')
,这里是单元测试输出的内容:
AssertionError: '' != '1\n2\n3\n4\n5'
+ 1
+ 2
+ 3
+ 4
+ 5
显然,脚本可以运行并输出正确的结果,但是 fakeOutput
没有捕捉到它。
使用patch
作为装饰器也不起作用:
from application import application
from io import StringIO
import unittest
from unittest.mock import patch
class TestApplication(unittest.TestCase):
@patch('sys.stdout', new_callable=StringIO)
def test_application_tasks(self):
expected = ['1','2','3','4','5']
application.parse_event('some event') # print() is called here within parse_event()
self.assertEqual(fakeOutput.getvalue().strip().split(), expected)
会输出完全相同的错误:AssertionError: Lists differ: [] != ['1', '2', '3', '4', '5']
os.system
运行s 一个新进程。如果您使用 monkey-patch sys.stdout
这会影响当前进程,但不会对任何新进程产生影响。
考虑:
import sys
from os import system
from io import BytesIO
capture = sys.stdout = BytesIO()
system("echo Hello")
sys.stdout = sys.__stdout__
print(capture.getvalue())
没有捕获任何内容,因为只有子进程写入了它的标准输出。没有任何内容写入您的 Python 进程的标准输出。
通常,避免 os.system
。相反,使用 subprocess
模块,它可以让您从 运行.
谢谢你,让-保罗·卡尔德隆。我意识到 os.system()
创建了一个完全不同的过程,因此我需要以不同的方式解决问题,只有在我发布问题之后:)
为了真正能够测试我的代码,我不得不使用 subprocess
而不是 os.system()
重写它。最后,我使用 subprocess_run_result = subprocess.run(task, shell=True, stdout=subprocess.PIPE)
然后使用 subprocess_run_result.stdout.strip().decode("utf-8")
.
在测试中,我只是创建了一个 class 的实例并调用了一个方法,该方法在子进程中运行任务。
我的整个重构代码和测试是here in this commit如果有人想看的话。
您的解决方案很好,只需使用 getvalue
代替,如下所示:
with patch("sys.stdout", new_callable=StringIO) as f:
print("Foo")
r = f.getvalue()
print("r: {r!r} ;".format(r=r))
r: "Foo" ;