Skip to content

Commit 9bdf5f9

Browse files
committed
14.1小节完成
1 parent d3226fb commit 9bdf5f9

File tree

1 file changed

+49
-53
lines changed

1 file changed

+49
-53
lines changed
Lines changed: 49 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -1,72 +1,68 @@
11
==============================
2-
14.1 测试输出到标准输出上
2+
14.1 测试stdout输出
33
==============================
44

55
----------
66
问题
77
----------
8-
You have a program that has a method whose output goes to standard Output
9-
(sys.stdout). This almost always means that it emits text to the screen. You’d like to
10-
write a test for your code to prove that, given the proper input, the proper output is
11-
displayed.
8+
你的程序中有个方法会输出到标准输出中(sys.stdout)。也就是说它会将文本打印到屏幕上面。
9+
你想写个测试来证明它,给定一个输入,相应的输出能正常显示出来。
1210

1311
|
1412
1513
----------
1614
解决方案
1715
----------
18-
Using the unittest.mock module’s patch() function, it’s pretty simple to mock out
19-
sys.stdout for just a single test, and put it back again, without messy temporary vari‐
20-
ables or leaking mocked-out state between test cases.
21-
Consider, as an example, the following function in a module mymodule:
22-
23-
# mymodule.py
24-
25-
def urlprint(protocol, host, domain):
26-
url = '{}://{}.{}'.format(protocol, host, domain)
27-
print(url)
28-
29-
The built-in print function, by default, sends output to sys.stdout. In order to test
30-
that output is actually getting there, you can mock it out using a stand-in object, and
31-
then make assertions about what happened. Using the unittest.mock module’s patch()
32-
method makes it convenient to replace objects only within the context of a running test,
33-
returning things to their original state immediately after the test is complete. Here’s the
34-
test code for mymodule:
35-
36-
from io import StringIO
37-
from unittest import TestCase
38-
from unittest.mock import patch
39-
import mymodule
40-
41-
class TestURLPrint(TestCase):
42-
def test_url_gets_to_stdout(self):
43-
protocol = 'http'
44-
host = 'www'
45-
domain = 'example.com'
46-
expected_url = '{}://{}.{}\n'.format(protocol, host, domain)
47-
48-
with patch('sys.stdout', new=StringIO()) as fake_out:
49-
mymodule.urlprint(protocol, host, domain)
50-
self.assertEqual(fake_out.getvalue(), expected_url)
16+
使用 ``unittest.mock`` 模块中的 ``patch()`` 函数,
17+
使用起来非常简单,可以为单个测试模拟 ``sys.stdout`` 然后回滚,
18+
并且不产生大量的临时变量或在测试用例直接暴露状态变量。
19+
20+
作为一个例子,我们在 ``mymodule`` 模块中定义如下一个函数:
21+
22+
.. code-block:: python
23+
24+
# mymodule.py
25+
26+
def urlprint(protocol, host, domain):
27+
url = '{}://{}.{}'.format(protocol, host, domain)
28+
print(url)
29+
30+
默认情况下内置的 ``print`` 函数会将输出发送到 ``sys.stdout`` 。
31+
为了测试输出真的在那里,你可以使用一个替身对象来模拟它,然后使用断言来确认结果。
32+
使用 ``unittest.mock`` 模块的 ``patch()`` 方法可以很方便的在测试运行的上下文中替换对象,
33+
并且当测试完成时候自动返回它们的原有状态。下面是对 ``mymodule`` 模块的测试代码:
34+
35+
.. code-block:: python
36+
37+
from io import StringIO
38+
from unittest import TestCase
39+
from unittest.mock import patch
40+
import mymodule
41+
42+
class TestURLPrint(TestCase):
43+
def test_url_gets_to_stdout(self):
44+
protocol = 'http'
45+
host = 'www'
46+
domain = 'example.com'
47+
expected_url = '{}://{}.{}\n'.format(protocol, host, domain)
48+
49+
with patch('sys.stdout', new=StringIO()) as fake_out:
50+
mymodule.urlprint(protocol, host, domain)
51+
self.assertEqual(fake_out.getvalue(), expected_url)
5152
5253
|
5354
5455
----------
5556
讨论
5657
----------
57-
The urlprint() function takes three arguments, and the test starts by setting up dummy
58-
arguments for each one. The expected_url variable is set to a string containing the
59-
expected output.
60-
To run the test, the unittest.mock.patch() function is used as a context manager to
61-
replace the value of sys.stdout with a StringIO object as a substitute. The fake_out
62-
variable is the mock object that’s created in this process. This can be used inside the
63-
body of the with statement to perform various checks. When the with statement com‐
64-
pletes, patch conveniently puts everything back the way it was before the test ever ran.
65-
It’s worth noting that certain C extensions to Python may write directly to standard
66-
output, bypassing the setting of sys.stdout. This recipe won’t help with that scenario,
67-
but it should work fine with pure Python code (if you need to capture I/O from such C
68-
extensions, you can do it by opening a temporary file and performing various tricks
69-
involving file descriptors to have standard output temporarily redirected to that file).
70-
More information about capturing IO in a string and StringIO objects can be found in
71-
Recipe 5.6.
58+
``urlprint()`` 函数接受三个参数,测试方法开始会先设置每一个参数的值。
59+
``expected_url`` 变量被设置成包含期望的输出的字符串。
60+
61+
``unittest.mock.patch()`` 函数被用作一个上下文管理器,使用 ``StringIO`` 对象来代替 ``sys.stdout`` .
62+
``fake_out`` 变量是在该进程中被创建的模拟对象。
63+
在with语句中使用它可以执行各种检查。当with语句结束时,``patch`` 会将所有东西恢复到测试开始前的状态。
64+
有一点需要注意的是某些对Python的C扩展可能会忽略掉 ``sys.stdout`` 的配置二直接写入到标准输出中。
65+
限于篇幅,本节不会涉及到这方面的讲解,它适用于纯Python代码。
66+
如果你真的需要在C扩展中捕获I/O,你可以先打开一个临时文件,然后将标准输出重定向到该文件中。
67+
更多关于捕获以字符串形式捕获I/O和 ``StringIO`` 对象请参阅5.6小节。
7268

0 commit comments

Comments
 (0)