Skip to content

Commit 346c6dc

Browse files
document test loop
1 parent ad6aafc commit 346c6dc

File tree

3 files changed

+46
-5
lines changed

3 files changed

+46
-5
lines changed

docs/index.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,7 @@ The missing ``async`` toolbox
5757
:hidden:
5858

5959
source/devel/contributing
60+
source/devel/testloop
6061
source/devel/publishing
6162

6263
The ``asyncstdlib`` library re-implements functions and classes of the Python

docs/source/devel/testloop.rst

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
===============
2+
Test Event Loop
3+
===============
4+
5+
.. py:module:: unittests.utility
6+
:synopsis: testing utilities
7+
8+
To facilitate event loop agnostic features, :py:mod:`asyncstdlib` includes
9+
its own custom event loop implementation for testing.
10+
This is provided as a simple decorator that is compatible with :py:mod:`pytest`,
11+
as well as a number of `async` commands specific to the event loop.
12+
13+
Event Loops
14+
===========
15+
16+
There are currently two event loops available for either simplicity or concurrency.
17+
In case of doubt, prefer :py:func:`~.multi_sync`.
18+
19+
.. autofunction:: sync(test_case: (...) -> (await) None) -> (...) -> None
20+
21+
.. autofunction:: multi_sync(test_case: (...) -> (await) None) -> (...) -> None
22+
23+
Async commands
24+
==============
25+
26+
.. autoclass:: PingPong
27+
28+
.. autoclass:: Schedule(*await Any)
29+
30+
.. autoclass:: Switch
31+
32+
.. autoclass:: Lock

unittests/utility.py

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@ class PingPong:
5050
5151
The coroutine yields to the event loop but is resumed
5252
immediately, without running others in the meantime.
53-
This is mainly useful for debugging the event loop.
53+
This is mainly useful for ensuring the event loop is used.
5454
"""
5555

5656
def __await__(self) -> "Generator[PingPong, Any, Any]":
@@ -68,7 +68,8 @@ def sync(test_case: Callable[..., Coroutine[None, Any, Any]]) -> Callable[..., N
6868
Mark an ``async def`` test case to be run synchronously
6969
7070
This emulates a primitive "event loop" which only responds
71-
to the :py:class:`PingPong` by sending it back.
71+
to the :py:class:`PingPong` by sending it back. This loop
72+
is appropriate for tests that do not check concurrency.
7273
"""
7374

7475
@wraps(test_case)
@@ -145,14 +146,21 @@ async def __aexit__(self, exc_type: Any, exc_val: Any, exc_tb: Any):
145146

146147

147148
def multi_sync(
148-
test_case: Callable[..., Coroutine[None, Any, Any]]
149+
test_case: Callable[..., Coroutine[None, Any, Any]], /
149150
) -> Callable[..., None]:
150151
"""
151152
Mark an ``async def`` test case to be run synchronously with children
152153
153-
This emulates a primitive "event loop" which only responds
154+
This provides a primitive "event loop" which only responds
154155
to the :py:class:`PingPong`, :py:class:`Schedule`, :py:class:`Switch`
155-
and :py:class:`Lock`.
156+
and :py:class:`Lock`. This loop is appropriate for tests that need
157+
to check concurrency.
158+
159+
It should be applied as a decorator on an ``async def`` function, which
160+
is then turned into a synchronous callable that will run the ``async def``
161+
function and all tasks it spawns.
162+
Other decorators, most prominently :py:func:`pytest.mark.parametrize`,
163+
can be applied around it.
156164
"""
157165

158166
@wraps(test_case)

0 commit comments

Comments
 (0)