标签: pytest-asyncio

使用 @pytest.fixture(scope="module") 和 @pytest.mark.asyncio

我认为下面的例子是一个非常常见的用例:

  1. 创建与数据库的连接一次
  2. 传递此连接以测试哪些插入数据
  3. 将连接传递给验证数据的测试。

改变@pytest.fixture(scope="module")原因的范围ScopeMismatch: You tried to access the 'function' scoped fixture 'event_loop' with a 'module' scoped request object, involved factories

此外,test_inserttest_find协程不需要 event_loop 参数,因为可以通过传递连接来访问循环。

任何想法如何解决这两个问题?

import pytest

@pytest.fixture(scope="function")  # <-- want this to be scope="module"; run once!
@pytest.mark.asyncio
async def connection(event_loop):
    """ Expensive function; want to do in the module scope. Only this function needs `event_loop`!
    """
    conn await = make_connection(event_loop)
    return conn


@pytest.mark.dependency()
@pytest.mark.asyncio
async def test_insert(connection, event_loop): …
Run Code Online (Sandbox Code Playgroud)

python pytest python-asyncio pytest-asyncio

7
推荐指数
2
解决办法
2519
查看次数

带有单例的 pytest-asyncio 会导致事件循环冲突

我使用 dbus 进行 IPC。为了在程序的整个生命周期中只有一辆总线,我在这里使用单例。为了演示,我连接到 NetworkManager,但可以交换。此外,我正在asyncio整个项目中使用。这是该模块的一个简约工作示例,它将突出显示下面描述的问题:

import asyncio  # noqa

from dbus_next.aio import MessageBus
from dbus_next import BusType


BUS = None


async def get_bus():
    # Returns a BUS singleton
    global BUS
    if not BUS:
        BUS = await MessageBus(bus_type=BusType(2)).connect()

    return BUS


async def introspect():
    # Get the dbus singleton and call a method on that singleton
    bus = await get_bus()
    return await bus.introspect(
        'org.freedesktop.NetworkManager',
        '/org/freedesktop/NetworkManager',
    )
Run Code Online (Sandbox Code Playgroud)

我正在使用pytestpytest-asyncio插件进行测试,除了这种情况之外,它的工作原理就像魅力一样。这是一个简约的工作测试模块:

import pytest

from example import introspect


@pytest.mark.asyncio
async def …
Run Code Online (Sandbox Code Playgroud)

python-3.x python-asyncio pytest-asyncio

7
推荐指数
1
解决办法
3522
查看次数

多个异步单元测试失败,但一一运行它们会通过

我有两个单元测试,如果我一一运行它们,它们就会通过。如果我在类级别运行它们,一个通过,另一个失败response = await ac.post(并显示错误消息:RuntimeError: Event loop is closed

@pytest.mark.asyncio
async def test_successful_register_saves_expiry_to_seven_days(self):
    async with AsyncClient(app=app, base_url="http://127.0.0.1") as ac:
        response = await ac.post(
            "/register/",
            headers={},
            json={
                "device_id": "u1",
                "device_type": DeviceType.IPHONE.value,
            },
        )
        query = device.select(whereclause=device.c.id == "u1")
        d = await db.fetch_one(query)
        assert d.expires_at == datetime.utcnow().replace(
            second=0, microsecond=0
        ) + timedelta(days=7)

@pytest.mark.asyncio
async def test_successful_register_saves_device_type(self):
    async with AsyncClient(app=app, base_url="http://127.0.0.1") as ac:
        response = await ac.post(
            "/register/",
            headers={},
            json={
                "device_id": "u1",
                "device_type": DeviceType.ANDROID.value,
            },
        )
        query = device.select(whereclause=device.c.id == "u1") …
Run Code Online (Sandbox Code Playgroud)

python pytest pytest-asyncio fastapi python-3.9

7
推荐指数
1
解决办法
2899
查看次数

使用 pytest-asyncio 测试 FastAPI 路由时出现“RuntimeError:事件循环已关闭”

我收到错误

运行时错误:事件循环已关闭

每次我尝试在测试中进行多个异步调用时。我已经尝试使用其他 Stack Overflow 帖子中的所有其他建议来重写固定event_loop装置,但没有任何效果。我想知道我错过了什么?

运行测试命令:

python -m pytest tests/ --asyncio-mode=auto
Run Code Online (Sandbox Code Playgroud)

要求.txt

pytest==7.1.2
pytest-asyncio==0.18.3
pytest-html==3.1.1
pytest-metadata==2.0.1
Run Code Online (Sandbox Code Playgroud)

测试.py

async def test_user(test_client_fast_api):
    assert 200 == 200

    # works fine
    request_first = test_client_fast_api.post("/first_route")

    # recieve RuntimeError: Event loop is closed
    request_second = test_client_fast_api.post("/second_route")
Run Code Online (Sandbox Code Playgroud)

测试.py

@pytest.fixture()
def event_loop():
    try:
        loop = asyncio.get_running_loop()
    except RuntimeError:
        loop = asyncio.new_event_loop()
    yield loop
    loop.close()
Run Code Online (Sandbox Code Playgroud)

python pytest pytest-asyncio

7
推荐指数
1
解决办法
5901
查看次数

如何为异步流服务器编写 pytest 夹具?

我一直在尝试学习 asyncio,但找不到任何创建可用于测试服务器代码的 pytest 夹具的示例。一旦服务器启动,我猜它会阻止其他一切,因此测试永远不会运行。pytest-asyncio 是否有办法在单独的线程中运行固定装置或其他东西?还是需要自己写线程代码?或者,还有更好的方法?下面是我一直在弄乱的一些代码。它是使用带有 pytest 固定装置的流文档从官方 TCP echo 服务器直接复制和粘贴并在最后进行测试:

import asyncio
import pytest


async def handle_echo(reader, writer):
    data = await reader.read(100)
    message = data.decode()
    addr = writer.get_extra_info('peername')

    print(f"Received {message!r} from {addr!r}")

    print(f"Send: {message!r}")
    writer.write(data)
    await writer.drain()

    print("Close the connection")
    writer.close()


async def main():
    server = await asyncio.start_server(
        handle_echo, '127.0.0.1', 8888)

    addr = server.sockets[0].getsockname()
    print(f'Serving on {addr}')

    async with server:
        await server.serve_forever()


@pytest.fixture(scope="session")
async def server():
    return await main()


@pytest.mark.asyncio
def test_something(server):
    assert False
Run Code Online (Sandbox Code Playgroud)

pytest python-3.x python-asyncio pytest-asyncio

6
推荐指数
1
解决办法
1770
查看次数

为什么 pytest 在测试简单的异步函数时挂起?

我有一个简单的回显服务器功能。如果我通过一个测试启动 pytest,一切都会正常,但如果我通过两个测试启动它,那么第二个测试就会挂起,等待服务器启动,我不明白为什么。这是完整的代码。

服务器:

async def handle_echo(reader, writer):
    data = await reader.read(100)

    message = data.decode()
    addr = writer.get_extra_info('peername')
    print(f"SERVER: Received {message!r} from {addr!r}")
    writer.write(data)
    await writer.drain()
    print(f"SERVER: Sent: {message!r}")

    writer.close()
    print("SERVER: Closed the connection")
Run Code Online (Sandbox Code Playgroud)

测试设置:

HOST = "localhost"


@pytest.fixture()
def event_loop():
    return asyncio.get_event_loop()


async def _async_wait_for_server(event_loop, addr, port):
    while True:
        a_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    try:
        await event_loop.sock_connect(a_socket, (addr, port))
        return
    except ConnectionRefusedError:
        await asyncio.sleep(0.001)

    finally:
        a_socket.close()


@pytest.fixture()
def server(event_loop):
    unused_tcp_port = 65432
    cancel_handle = asyncio.ensure_future(main(unused_tcp_port), loop=event_loop)
    event_loop.run_until_complete(asyncio.wait_for(
        _async_wait_for_server(event_loop, HOST, unused_tcp_port), 5.0)) …
Run Code Online (Sandbox Code Playgroud)

python pytest python-asyncio pytest-asyncio

6
推荐指数
0
解决办法
1069
查看次数

Pytest 返回事件循环已关闭(FastAPI)

使用小型 FastAPI 应用程序,但在针对我的端点运行 pytest 时出现“事件循环关闭”运行时错误。

我有一些像这样的数据库操作AsyncIOMotorClient

async def get_user_data(token: str, client = MongoClient()):
    """ Get user data from database for given token """
    return await client.db.user_data.find_one({"token": token})
Run Code Online (Sandbox Code Playgroud)

还有一些像这样的基本测试:

def test_read_user_data(auth_token):
    response = client.post("/crud/read",
        json={"token":"xxx"},
        headers=HEADERS(auth_token)
    )
    print(response.json())
    assert response.status_code == 200
Run Code Online (Sandbox Code Playgroud)

一组中的第一个测试运行良好,但第二个测试在其中一个数据库操作上总是失败:

self = <_UnixSelectorEventLoop running=False closed=True debug=False>

    def _check_closed(self):
        if self._closed:
>           raise RuntimeError('Event loop is closed')
E           RuntimeError: Event loop is closed

/usr/lib/python3.8/asyncio/base_events.py:508: RuntimeError
================================================== short test summary info ==================================================
FAILED test_routes.py::test_read_user_data - RuntimeError: Event loop …
Run Code Online (Sandbox Code Playgroud)

pytest pytest-asyncio fastapi

6
推荐指数
0
解决办法
1498
查看次数

aiohttp_client - 运行时错误:超时上下文管理器应该在任务中使用

我在做什么

我正在通过构建一个 REST api 来学习 aiohttp,我正在使用 Pytest(及其 async 和 aiohttp 插件)进行测试。

对于我的第一次测试(我从一开始就使用 TDD)我有以下代码:

@pytest.mark.asyncio
async def test_handle_user_create(
    aiohttp_client, init_test_app, create_test_user_table
):
    payload = {
        "email": "tintin@gmail.com",
        "username": "Tintin",
        "password": "y0u != n00b1e",
    }
    client = await aiohttp_client(init_test_app)
    resp = await client.post("/users/", json=payload)
    ...
Run Code Online (Sandbox Code Playgroud)
  • aiohttp_client 是客户端装置来自 pytest-aiohttp
  • init_test_app 是一个固定装置,它基本上反映了我将要构建的应用程序
  • create_test_user_table 是我在测试数据库中为用户创建表的夹具

它有什么问题

我的第一个测试是在上面代码块的最后一行抛出以下运行时错误:

_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ …
Run Code Online (Sandbox Code Playgroud)

python python-asyncio aiohttp pytest-aiohttp pytest-asyncio

5
推荐指数
0
解决办法
1145
查看次数

Python 3.10 中有 setUpClass 的异步等效项吗?

我一直在用来unittest.IsolatedAsyncioTestCase测试我的异步方法。我一直在使用setUpClass,asyncSetUp来创建固定装置并asyncTearDown进行清理。到目前为止一切进展顺利:-)

但现在我有一个新的要求,即每个测试类异步创建一些固定装置,并在整个测试方法中使用它。

我知道setUpClass每个测试类运行一次,setUp每个测试方法运行一次。

asyncSetUp是异步等价于setUp. 但我似乎没有找到异步等价物setUpClass

那么,每次测试异步创建和清理夹具的最佳方法是什么?

我在https://docs.python.org/3/library/unittest.html#unittest.TestCase.setUpClass尝试了官方的unittest文档,但它只记录了有关asyncSetUp.

我使用的是 Python 3.10 并使用 pytest。

pytest python-3.x pytest-asyncio

5
推荐指数
0
解决办法
524
查看次数

如何将“url_route”键/值添加到“scope”中进行测试?

我正在测试我的消费者,它使用scope['url_route']但使用HttpCommunicatoror ApplicationCommunicator,该参数未设置。我该如何设置这个参数?测试文档非常有限,并且没有关于此https://channels.readthedocs.io/en/latest/topics/testing.html的任何文档。

测试.py

from channels.testing import HttpCommunicator
import pytest

from my_app import consumers

@pytest.mark.asyncio
async def test_consumers():
    communicator = HttpCommunicator(consumers.MyConsumer, 'GET', '/project/1')
    response = await communicator.get_response()
    assert response['status'] == 400
Run Code Online (Sandbox Code Playgroud)

my_app.py

import json

from channels.db import database_sync_to_async
from channels.generic.http import AsyncHttpConsumer

from projects import model

class MyConsumer(AsyncHttpConsumer):
    async def handle(self, body):
        _id = int(self.scope['url_route']['kwargs'].get('project_id', 1))
        record = await database_sync_to_async(models.Project.objects.get)(id=_id)
        data = json.dumps({"id": _id})
        await self.send_response(200, data.encode('utf8'))
Run Code Online (Sandbox Code Playgroud)

python-asyncio django-channels pytest-asyncio

4
推荐指数
1
解决办法
1328
查看次数

'pytest.mark.asyncio' 用于什么?

我不明白装饰器@pytest.mark.asyncio可以用于哪些目的。

我试图运行下面的代码片段与pytestpytest-asyncio插件安装失败了,所以我订立无装饰是pytest收集测试协同程序。为什么会这样存在?

async def test_div():
    return 1 / 0
Run Code Online (Sandbox Code Playgroud)

pytest python-3.x pytest-asyncio

4
推荐指数
2
解决办法
2653
查看次数

使用 WebSocketCommunicator 在 Django Channels v2 测试中进行身份验证

在为我的聊天消费者编写测试的过程中,我遇到了无法使用 WebSocketCommunicator 在测试中进行身份验证的问题。我有自定义 JwtTokenAuthMiddleware,它通过在请求查询中使用令牌来实现套接字中的身份验证,因为据我所知,使用授权标头进行适当的身份验证尚不可能。你们能给我建议或者向我提供我在网上找不到的示例代码吗?顺便说一句,我的聊天工作没有问题。另外测试应该完全没问题,我从官方文档 Django Channels 2.x 测试中获取了指南。

--JwtTokenAuthMiddlewate--

class JwtTokenAuthMiddleware:
    def __init__(self, inner):
        self.inner = inner

    def __call__(self, scope):
        close_old_connections()
        try:
            raw_token = scope['query_string'].decode().split('=')[1]
            auth = JWTAuthentication()
            validated_token = auth.get_validated_token(raw_token)
            user = auth.get_user(validated_token)
            scope['user'] = user
        except (IndexError, InvalidToken, AuthenticationFailed):
            scope['user'] = AnonymousUser()
        return self.inner(scope)


JwtTokenAuthMiddlewareStack = lambda inner: JwtTokenAuthMiddleware(AuthMiddlewareStack(inner))
Run Code Online (Sandbox Code Playgroud)

--测试示例--

@pytest.mark.django_db(transaction=True)
@pytest.mark.asyncio
async def test_trainer_auth_success():
    room = await database_sync_to_async(RoomFactory.create)()
    trainer = room.trainer
    trainer_token = await sync_to_async(get_token_for_user)(trainer.user)
    room_url = f'ws/room/{room.id}/'

    trainer_communicator = WebsocketCommunicator(application, f'{room_url}?t={trainer_token}')
    connected, _ = await trainer_communicator.connect() …
Run Code Online (Sandbox Code Playgroud)

django python-3.x pytest-django django-channels pytest-asyncio

4
推荐指数
1
解决办法
1736
查看次数