Python:编写控制台打印的unittest
函数Python:编写控制台打印的unittest,python,python-2.7,unit-testing,console,python-unittest,Python,Python 2.7,Unit Testing,Console,Python Unittest,函数foo打印到控制台。我想测试控制台打印。如何在python中实现这一点 需要测试此函数,没有返回语句: def foo(inStr): print "hi"+inStr 我的测试: def test_foo(): cmdProcess = subprocess.Popen(foo("test"), stdout=subprocess.PIPE) cmdOut = cmdProcess.communicate()[0] self.assertEquals("hi
foo
打印到控制台。我想测试控制台打印。如何在python中实现这一点
需要测试此函数,没有返回语句:
def foo(inStr):
print "hi"+inStr
我的测试:
def test_foo():
cmdProcess = subprocess.Popen(foo("test"), stdout=subprocess.PIPE)
cmdOut = cmdProcess.communicate()[0]
self.assertEquals("hitest", cmdOut)
只需将
sys.stdout
临时重定向到StringIO
对象,即可轻松捕获标准输出,如下所示:
import StringIO
import sys
def foo(inStr):
print "hi"+inStr
def test_foo():
capturedOutput = StringIO.StringIO() # Create StringIO object
sys.stdout = capturedOutput # and redirect stdout.
foo('test') # Call unchanged function.
sys.stdout = sys.__stdout__ # Reset redirect.
print 'Captured', capturedOutput.getvalue() # Now works as before.
test_foo()
该程序的输出为:
Captured hitest
显示重定向成功捕获了输出,并且您能够将输出流恢复到开始捕获之前的状态
请注意,如问题所示,上面的代码是针对Python2.7的。Python 3略有不同:
import io
import sys
def foo(inStr):
print ("hi"+inStr)
def test_foo():
capturedOutput = io.StringIO() # Create StringIO object
sys.stdout = capturedOutput # and redirect stdout.
foo('test') # Call function.
sys.stdout = sys.__stdout__ # Reset redirect.
print ('Captured', capturedOutput.getvalue()) # Now works as before.
test_foo()
这个Python3答案使用了。它还使用一个可重用的助手方法assert\stdout
,尽管这个助手特定于被测试的函数
import io
import unittest
import unittest.mock
from .solution import fizzbuzz
class TestFizzBuzz(unittest.TestCase):
@unittest.mock.patch('sys.stdout', new_callable=io.StringIO)
def assert_stdout(self, n, expected_output, mock_stdout):
fizzbuzz(n)
self.assertEqual(mock_stdout.getvalue(), expected_output)
def test_only_numbers(self):
self.assert_stdout(2, '1\n2\n')
请注意,mock\u stdout
arg由unittest.mock.patch
decorator自动传递给assert\u stdout
方法
一个通用的TestStdout
类,可能是一个mixin,原则上可以从上面得到
对于那些使用Python的人≥3.4也存在,但它似乎没有任何好处。如果您碰巧使用,它有内置的输出捕获功能。示例(pytest
样式测试):
您也可以将其与unittest
测试类一起使用,尽管您需要将fixture对象传递到测试类中,例如通过自动使用fixture:
import unittest
import pytest
class TestSpam(unittest.TestCase):
@pytest.fixture(autouse=True)
def _pass_fixtures(self, capsys):
self.capsys = capsys
def test_eggs(self):
eggs()
captured = self.capsys.readouterr()
self.assertEqual('eggs\n', captured.out)
查看更多信息。您还可以使用模拟软件包,如下所示,这是 来自模拟导入修补程序的
姓名:
打印('Hello',name)
@修补程序('builtins.print')
def测试(模拟打印):
#实际测试
问候(‘约翰’)
mock\u print.assert\u使用('Hello','John')调用\u
问候(‘埃里克’)
mock_print.assert_用('Hello','Eric')调用_
的@acumones说明:
它还使用一个可重用的助手方法assert\stdout,尽管这个助手特定于被测试的函数。
粗体部分似乎是一个很大的缺点,因此我将执行以下操作:
# extend unittest.TestCase with new functionality
class TestCase(unittest.TestCase):
def assertStdout(self, expected_output):
return _AssertStdoutContext(self, expected_output)
# as a bonus, this syntactical sugar becomes possible:
def assertPrints(self, *expected_output):
expected_output = "\n".join(expected_output) + "\n"
return _AssertStdoutContext(self, expected_output)
class _AssertStdoutContext:
def __init__(self, testcase, expected):
self.testcase = testcase
self.expected = expected
self.captured = io.StringIO()
def __enter__(self):
sys.stdout = self.captured
return self
def __exit__(self, exc_type, exc_value, tb):
sys.stdout = sys.__stdout__
captured = self.captured.getvalue()
self.testcase.assertEqual(captured, self.expected)
这样可以实现更好、更可重用的功能:
# in a specific test case, the new method(s) can be used
class TestPrint(TestCase):
def test_print1(self):
with self.assertStdout("test\n"):
print("test")
通过使用直接的上下文管理器。(可能还需要将“\n”
附加到预期的\u输出
,因为print()
默认情况下会添加换行符。请参见下一个示例…)
此外,这个非常好的变体(用于任意数量的打印!)
现在可以了。复制tl;dr使用future或assert在替换的标准文件上将打印转换为内置函数我不想模拟任何东西。实际上,我的实际
foo
接受大约8个参数,并返回一个json。我还想测试一下这一点。在Python 3.7中,您现在在Python3.8.6
中使用import io
和io.SocketIO()
,使用import io
和io.StringIO()
。对于SocketIO
我得到了属性错误:模块“io”没有属性“SocketIO”
@EnriqueRené:我不确定我是否理解您的评论。自从Python3部分在2017年添加以来,我在Python3的答案中有了io.StringIO()
。没有任何版本提到过SocketIO
@paxdiablo我的评论是关于上述@Alex评论的,据我所知,我也可以使用SocketIO
。我尝试了这个建议,得到了AttributeError
。由于您的类名为TestCase,我假设您正在对unittest.TestCase进行子类化以扩展它,并且def test_print(self)是TestPrintClass(TestCase)类的一部分,其中TestCase是您的扩展实现。对吗?--也许在这里说的是显而易见的,但这是我读代码时突然想到的绝对正确的东西。很抱歉,示例中缺少了TestPrintClass
。我会加进去的!
# in a specific test case, the new method(s) can be used
class TestPrint(TestCase):
def test_print1(self):
with self.assertStdout("test\n"):
print("test")
def test_print2(self):
with self.assertPrints("test1", "test2"):
print("test1")
print("test2")