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
149import asyncio
1510import 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
2924import asyncio
3025import 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
6450import aiomas
6551
@@ -89,50 +75,41 @@ server.close()
8975aiomas.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
10287domain 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
137114import tempfile
138115import 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
173150import 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' ])
224192def 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
247210import asyncio
248211import 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
322284import 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