Skip to content

Commit 54dffa0

Browse files
committed
add translation of 'Advanced asyncio testing'
1 parent e9e6f24 commit 54dffa0

3 files changed

Lines changed: 52 additions & 85 deletions

File tree

Others/README.md

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -10,19 +10,22 @@
1010

1111
使用Twilio Lookup来对电话号码进行常规操作,例如验证有效性,获取运营商信息等。有更多更好的想法,不要忘记联系原作者进行分享~~
1212

13-
- [用Python玩转Worcester Wave恒温器-第一部分](./用Python玩转Worcester Wave恒温器-第一部分.md)
13+
- 用Python玩转Worcester Wave恒温器
1414

15-
智能家居盛行的现在,你也可以控制自己的家电。如果你的电器支持移动app控制,那么不知道如何踏出hack the life的第一步,可以看看这篇文章,或许你可以有一种新思路……
15+
* [第一部分](./用Python玩转Worcester Wave恒温器-第一部分.md)
1616

17-
- [用Python玩转Worcester Wave恒温器-第二部分](./用Python玩转Worcester Wave恒温器-第二部分.md)
17+
智能家居盛行的现在,你也可以控制自己的家电。如果你的电器支持移动app控制,那么不知道如何踏出hack the life的第一步,可以看看这篇文章,或许你可以有一种新思路……
1818

19-
紧接着第一部分,我们看看如何用starttls-mitm进行合法的中间人攻击以破解app和服务器之间加密的通信,看看如何使用反编译器反编译apk以获得消息中的信息加密算法以进行逆向,最终获得完整的明文交互信息……
19+
* [第二部分](./用Python玩转Worcester Wave恒温器-第二部分.md)
2020

21-
- [用Python玩转Worcester Wave恒温器-第三部分](./用Python玩转Worcester Wave恒温器-第三部分.md)
22-
23-
收尾章节。我们可以看到如何利用破解出来的信息达到实际的控制。并且,作者还在Github上分享了他的源代码!
21+
紧接着第一部分,我们看看如何用starttls-mitm进行合法的中间人攻击以破解app和服务器之间加密的通信,看看如何使用反编译器反编译apk以获得消息中的信息加密算法以进行逆向,最终获得完整的明文交互信息……
22+
23+
* [第三部分](./用Python玩转Worcester Wave恒温器-第三部分.md)
24+
25+
收尾章节。我们可以看到如何利用破解出来的信息达到实际的控制。并且,作者还在Github上分享了他的源代码!
2426

2527
- [psutil 4.0.0以及如何获得Python中“真正的”进程内存和环境](./psutil 4.0.0以及如何获得Python中“真正的”进程内存和环境.md)
28+
2629
描述如何用psutil 4.0.0获得“真正的”进程内存度量以及进程环境变量的一些信息。
2730

2831
- [Python依赖关系分析](./Python依赖关系分析.md)

Python Common/README.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,3 +39,7 @@
3939
- [Python 201 – 什么是双端队列(deque)](./Python 201 – 什么是双端队列(deque).md)
4040

4141
作为collections模块中的一员,双端队列(deque)是一个能够实现栈和队列的。本文介绍了关于它的一些基本知识。
42+
43+
- [高级asyncio测试](./高级asyncio测试.md)
44+
45+
本文介绍了如何使用pytest-asyncio和fixture进行高级的asyncio测试。

Python Common/高级asyncio测试.md

Lines changed: 38 additions & 78 deletions
Original file line numberDiff line numberDiff line change
@@ -2,14 +2,9 @@
22

33
---
44

5-
In my [last article](https://stefan.sofa-rockers.org/2015/04/22/testing-coroutines/), I showed how pytest’s fixture system and plug-in
6-
infrastructure can help you with writing cleaner and better tests. Fixtures
7-
allow you to create a clean event loop instance for every test case. The
8-
plug-in system allows you to write test functions that are actually asyncio
9-
coroutines. While I was working on that articel, _Tin Tvrtkovic_ created the
10-
plug-in [pytest-asyncio](https://pypi.python.org/pypi/pytest-asyncio).
11-
12-
In short, it lets you do this:
5+
在我[上一篇文章中](https://stefan.sofa-rockers.org/2015/04/22/testing-coroutines/),我显示了pytest的Fixture系统和插入式基础架构是如何帮你编写更加干净优秀的测试的。Fixture允许你为每个测试用例创建一个干净的事件循环实例。而插入式系统允许你编写实际上市asyncio协程的测试函数。在我写那篇文章时,_Tin Tvrtkovic_ 创建了插入式[pytest-asyncio](https://pypi.python.org/pypi/pytest-asyncio)
6+
7+
总之,它让你可以这样:
138
```py
149
import asyncio
1510
import time
@@ -24,7 +19,7 @@ def test_coro(event_loop):
2419
assert after - before >= 0.1
2520
```
2621

27-
Instead of this:
22+
来取代这样:
2823
```py
2924
import asyncio
3025
import time
@@ -42,24 +37,15 @@ def test_coro():
4237
loop.close()
4338
```
4439

45-
So using _pytest-asyncio_ clearly improves your test (and there is even more,
46-
what this plug-in does!).
40+
因此,使用_pytest-asyncio_显然改善你的测试 (当然,这个插件还能做更多东西!)。
4741

48-
While I have been working on [aiomas](https://aiomas.readthedocs.org), some additional requirements came up
49-
that were not so easily covered. What _aiomas_ basically does is adding three
50-
layers of abstraction around the asyncio transports:
42+
在我努力做[aiomas](https://aiomas.readthedocs.org)时,一些无法简单涵盖的额外需求出现了。_aiomas_基本上做的是在asyncio传输周围增加三个抽象层:
5143

52-
1. The _channel_ layer lets you send JSON or MsgPack encoded messages in
53-
a request-reply manner. This layer uses a custom protocol that works with
54-
different kinds of transports: TCP sockets, Unix domain sockets and custom
55-
transport called _local queue_.
56-
2. The _RPC_ layer creates a remote-procedure-call system on top of the
57-
_channel_ layer.
58-
3. The _agent_ layer (for multi-agent systems) hides even more of the
59-
networking-related stuff and lets you basically write classes that call
60-
methods of other classes over a network connection.
44+
1. _channel_层允许你以一种请求-应答方式发送JSON或者MsgPack编码消息。这一层使用了与不同种类的传输一起工作的自定义协议:TCP套接字,Unix域套接字和名为_本地队列_的自定义传输。
45+
2. _RPC_层在_channel_层之上创建了一个远程过程调用系统。
46+
3. _agent_层(为多代理系统)隐藏了更多的网络相关的东西,并基本上让你编写那些通过网络连接调用其他类方法的类。
6147

62-
Here is a simple example of how the _channel_ layer works:
48+
这里是_channel_层如何工作的一个简单例子:
6349
```py
6450
import aiomas
6551

@@ -89,50 +75,41 @@ server.close()
8975
aiomas.run(server.wait_closed())
9076
```
9177

92-
## Requirements for our tests
78+
## 对于我们的测试的要求
9379

94-
So with this in mind, I had the following requirements for my tests:
80+
所以,考虑到这一点,对于我的测试,我有以下要求:
9581

96-
1. I need a clean event loop instance for every test.
82+
1. 对于每个测试,我需要一个干净的事件循环实例。
9783

98-
This can be solved with the `event_loop` fixture provided by
99-
_pytest-asyncio_.
84+
这可以使用_pytest-asyncio_提供的`event_loop`来解决。
10085

101-
2. Every test should be run with every transport available (TCP socket, Unix
86+
2. 每一个测试都应该使用一个可用的传输来运行 (TCP socket, Unix
10287
domain socket, …).
10388

104-
This could in theory be solved with the `pytest.mark.parametrize()`
105-
decorator (but not in my case as we will see later).
89+
这在理论上可以使用`pytest.mark.parametrize()`装饰器解决 (稍后我们会看到,在我的例子中并不是这样的)。
10690

107-
3. Every test needs a client coroutine. Ideally, this would be the test itself.
91+
3. 每一个测试需要一个客户端协程。理想情况下,这将是测试本身。
10892

109-
_pytest-asyncio’s_ `pytest.mark.asyncio` decorator solves this.
93+
_pytest-asyncio的_ `pytest.mark.asyncio`装饰器解决了这个问题。
11094

111-
4. Every test needs a server with a custom callback for client connections.
112-
Servers must be cleanly shut down no matter what the outcome of the test is.
95+
4. 每个测试需要一个带有与客户端连接相对应的自定义回调的服务器。不管测试输出是什么,都必须彻底关闭服务器
11396

114-
It would seem that a fixture would do the job, but every server needs a test
115-
specific callback for handling client connections. This makes it a lot harder.
97+
看起来一个fixture可以做到这点,但每个服务器都需要一个特定测试回调来处理客户端连接。这使得它困难得多。
11698

117-
5. I don’t want any “address already in use” errors if one test fails badly.
99+
5. 如果一个测试失败了,我不希望看到任何“address already in use”错误。
118100

119-
_pytest-asyncio’s_ `unused_tcp_port` fixture comes to help.
101+
_pytest-asyncio的_`unused_tcp_port`fixture可以一用。
120102

121-
6. I don’t want to use `loop.run_until_complete()` all the time.
103+
6. 我不想一直使用`loop.run_until_complete()`
122104

123-
Again, the `pytest.mark.asyncio` decorator solves this.
105+
再次,`pytest.mark.asyncio`装饰器解决了这个问题。
124106

125-
To wrap up what remains to be solved: Every test needs at least two fixtures
126-
(one for the event loop, one for the address type), but I want to combine them
127-
as a single fixture. Creating a fixture for setting up a server would also be
128-
nice, but how can we do this?
107+
总结有待解决的问题:每个测试都需要至少两个fixture(一个用于事件循环,另一个用于地址类型),但我想将它们结合成一个单一的fixture。为建立服务器创建一个fixture也是不错的,但如何才能做到这一点呢?
129108

130109

131-
## Our first approach
110+
## 第一个种方法
132111

133-
The first thing we can do is to wrap the loop and the address type in
134-
a fixture. We’ll call it _ctx_ (short for _test context_). With fixture
135-
parameters, it is also easy to create one fixture instance for every address type:
112+
我们能做的第一件事是将循环和地址类型都放在一个fixture中。我们将称其为_ctx_(_测试上下文(test context)_的缩写)。使用fixture参数,也可以容易地为每个地址类型创建一个fixture实例:
136113
```py
137114
import tempfile
138115
import py
@@ -168,7 +145,7 @@ def short_tmpdir():
168145
yield py.path.local(tdir)
169146
```
170147

171-
This lets us write our tests like this:
148+
这让我们这样编写我们的测试:
172149
```py
173150
import aiomas
174151

@@ -197,28 +174,19 @@ async def test_channel(ctx):
197174
assert results == ['ohai', 'cya']
198175
```
199176

200-
This works already very nicely and every test using the `ctx` fixture is run
201-
once for every address type.
177+
This works already very nicely and every test using the 这已经工作良好,而且使用`ctx`fixture的每个测试都为每个地址类型运行一次。
202178

203-
However, two problems remain:
179+
然而,有两个问题仍然存在:
204180

205-
1. Our `ctx` fixture always requires an unused TCP port _and_ a temporary
206-
directory – although we only need one of both in each case.
207-
2. Setting up the server (and closing it) also involves some code which will be
208-
the same for every test and should thus be moved into a fixture. However,
209-
a `server` fixture won’t work directly, because every server needs a test
210-
specific callback as you can see in the line where we create the server
211-
(`server = await ...`). But without a `server` fixture, we can’t have
212-
a tear-down method for it …
181+
1. 我们的`ctx`fixture总是需要一个未使用的TCP端口以及一个临时目录 —— 虽然在每种情况下,我们只需要其中之一。
182+
2. 建立服务器 (和关闭它) 也涉及一些代码,这些代码对于每个测试都是一样的,因此应该被移到一个fixture中。然而,一个`server`fixture并不直接工作,因为每个服务器需要一个指定测试的回调,正如你在我们创建服务器的那一行(`server = await ...`)可以看到的。但没有`server`fixture,对此我们就无法拆除……
213183

214-
Let’s see how we can tackle these issues.
184+
让我们看看我们如何能够解决这些问题。
215185

216186

217-
## Approach number two
187+
## 第二种方法
218188

219-
The first problem can be solved by using the `getfuncargvalue()` method of
220-
the _request_ object that our fixture receives. Using this method, we can
221-
manually call a fixture function:
189+
第一个问题可以通过我们的fixture接收的_request_对象的`getfuncargvalue()`方法来解决。使用这个方法,我们可以手工调用一个fixture函数:
222190
```py
223191
@pytest.fixture(params=['tcp', 'unix'])
224192
def ctx(request, event_loop):
@@ -237,12 +205,7 @@ def ctx(request, event_loop):
237205
return ctx
238206
```
239207

240-
To help with issue number two, we can extend our `Context` class that is
241-
passed into every test. We add a method
242-
`Context.start_server(client_handler)` that we can call from within our
243-
tests. We also add a finalize/teardown part to our `ctx` fixture that will
244-
close the server once we are done. And while we are at it, we’ll also create
245-
some more shortcut functions:
208+
要解决第二个问题,我们可以扩展传递给每个测试的`Context`类。我们添加一个方法`Context.start_server(client_handler)`,在我们的测试中,我们可以调用这个方法。我们还添加了一个finalize/teardown部分到我们的`ctx` fixture中,一旦完成了,它将关闭服务器。而我们还需要创建一些快捷功能:
246209
```py
247210
import asyncio
248211
import tempfile
@@ -316,8 +279,7 @@ def ctx(request, event_loop):
316279
return_exceptions=True))
317280
```
318281

319-
With this extra functionality, our test case becomes a lot shorter, easier to
320-
read, and more reliable:
282+
使用这个额外的功能,我们的测试用例变得短得多,容易读得多,并且更加可靠:
321283
```py
322284
import aiomas
323285

@@ -340,6 +302,4 @@ async def test_channel(ctx):
340302
assert results == ['ohai', 'cya']
341303
```
342304

343-
The `ctx` fixture (and the associated `Context` class) is indeed not the
344-
shortest fixture I ever wrote, but it helped me to remove approx. 200 lines of
345-
boilerplate code from my tests (apart from making them more readable and maintainable).
305+
`ctx` fixture (和相关的`Context`类)确实不是我写过的最短的fixture,但它帮助我从我的测试中移除了约200行的样板文件代码(除了让它们更加可读和可维护)。

0 commit comments

Comments
 (0)