You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何让pytest-bdd与pytest-asyncio兼容实现异步测试?

解决pytest-bdd的then步骤与pytest.mark.asyncio兼容问题

我要做的是创建一个测试流程:先给设备设置一些值,之后每隔固定时间多次查询这些值,断言查询结果和设置值一致。因为不能等一次响应回来再继续,所以必须异步执行查询和断言,但现在没法把pytest-bdd的then函数和pytest.mark.asyncio结合起来,求解决办法。


两次失败的尝试

尝试1:给then步骤加asyncio标记报错

直接给then装饰的异步函数加@pytest.mark.asyncio,代码如下:

@pytest.mark.asyncio
@then(parsers.parse("The query result for {setting} is {value:n}"))
@then(parsers.parse("The query result for {setting} is {value:bool}", extra_types={"bool": bool}))
async def test_get_value(destination, setting, value):
    responses = await run_queries(destination, setting)
    for response in responses:
        assert response == value

配套的run_queries函数:

async def run_queries(destination: int, query_name: str, connection_file: str) -> List[int]:
    # 创建包含query_name、connection file和destination的自定义消息对象
    responses = client.execute(message) # 执行查询并收集响应,这部分功能正常
    query_result = []

    for response in responses:
        if response.tid == tid: # 校验是否拿到正确响应
            query_result.append(response.value[0])

    return query_result

结果触发错误:coroutine 'test_get_value' was never awaited

尝试2:给场景加asyncio标记,场景不执行

给@scenario装饰的测试函数加@pytest.mark.asyncio,代码:

@scenario('../features/scenario_fixture.feature', 'Hope this works')
@pytest.mark.asyncio
def test_query():
    pass

对应的Feature文件:

Feature: Scenario test
  Scenario: Hope this works
    Then The query result for setting is 100

结果场景完全不运行。


可行的解决方案

pytest-bdd本身不直接支持异步then步骤,但可以通过两种方式绕开限制:

方案1:用异步夹具封装异步逻辑

把异步查询逻辑放到带@pytest.mark.asyncio的夹具中,pytest会自动处理异步执行,再把结果传给同步的then步骤:

import pytest
from pytest_bdd import then, parsers, scenario

@pytest.fixture(scope="function")
async def query_results(destination, setting):
    return await run_queries(destination, setting)

@then(parsers.parse("The query result for {setting} is {value:n}"))
@then(parsers.parse("The query result for {setting} is {value:bool}", extra_types={"bool": bool}))
def check_query_results(query_results, value):
    for response in query_results:
        assert response == value

@scenario('../features/scenario_fixture.feature', 'Hope this works')
def test_query():
    pass

方案2:在同步步骤中手动运行异步函数

如果不想用夹具,直接在同步then步骤里用asyncio.run()执行异步逻辑:

import asyncio
from pytest_bdd import then, parsers, scenario

@then(parsers.parse("The query result for {setting} is {value:n}"))
@then(parsers.parse("The query result for {setting} is {value:bool}", extra_types={"bool": bool}))
def test_get_value(destination, setting, value):
    responses = asyncio.run(run_queries(destination, setting))
    for response in responses:
        assert response == value

@scenario('../features/scenario_fixture.feature', 'Hope this works')
def test_query():
    pass

注意:如果测试环境已存在事件循环(比如用了pytest-asyncio的默认循环),改用asyncio.get_running_loop().run_until_complete()避免循环冲突。

内容的提问来源于stack exchange,提问作者FroMoSouOmou

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.17 11:37:47