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

使用Pytest+async playwright测试:首个测试通过后进程永久挂起

问题:async_playwright + pytest_asyncio 模块级fixture导致测试挂起

我使用async_playwright编写UI测试,通过pytest_asyncio创建module级别的browser和page共享fixture以复用实例,但执行pytest tests时,首个测试用例通过后进程永久挂起。

代码实现

conftest.py

import pytest_asyncio
import asyncio
from playwright.async_api import async_playwright

from src.page_object.factory.playwright import PWPageOjectFactory


@pytest_asyncio.fixture(scope="session")
def event_loop(request):
    """Create an instance of the default event loop for each test case."""
    loop = asyncio.get_event_loop_policy().new_event_loop()
    yield loop
    loop.close()


@pytest_asyncio.fixture(scope="module")
async def browser():
    async with async_playwright() as p:
        browser = await p.chromium.launch()
        yield browser
        await browser.close()


@pytest_asyncio.fixture(scope="module")
async def page(browser):
    factory = PWPageOjectFactory("https://www.google.com", browser)
    print(factory.url)
    page = await factory.create_page_object()
    print(page)
    return page

测试文件代码

import pytest

from src.page_object.element.playwright import PWElement
from src.page_object.page.playwright import PWPageObject

pytest_plugins = ("pytest_asyncio",)


@pytest.mark.asyncio
async def test_po_factory(page):
    assert page is not None
    assert isinstance(page, PWPageObject)


@pytest.mark.asyncio
async def test_get_active_element(page):
    element = await page.get_active_element()
    assert element is not None
    assert isinstance(element, PWElement)


@pytest.mark.asyncio
async def test_navigate(page):
    element = await page.get_active_element()
    await page.navigate_forward()
    new_element = await page.get_active_element()
    assert element.get_attribute("id") != new_element.get_attribute("id")
    await page.navigate_backward()
    new_element = await page.get_active_element()
    assert element.get_attribute("id") == new_element.get_attribute("id")

已尝试操作

  • 将module级fixture移至测试文件,问题依旧;
  • 删除conftest.py中的event_loop fixture,结果无变化;
  • 尝试不使用Playwright的pytest插件运行测试;
  • 查找类似问题但未找到有效解答。

环境信息

  • 系统:Windows
  • 环境:conda

解决方案

1. 修正Playwright启动/关闭方式

原browser fixture使用async with async_playwright(),在module级fixture场景下可能导致上下文提前回收,改为手动启动和停止Playwright:

@pytest_asyncio.fixture(scope="module")
async def browser():
    p = await async_playwright().start()
    browser = await p.chromium.launch()
    yield browser
    await browser.close()
    await p.stop()

2. 调整Windows下的Event Loop策略

Windows默认的ProactorEventLoop对部分异步操作支持不佳,切换为SelectorEventLoopPolicy:
在conftest.py开头添加:

import sys
import asyncio
from asyncio import WindowsSelectorEventLoopPolicy, WindowsProactorEventLoopPolicy

if sys.platform.startswith('win') and isinstance(asyncio.get_event_loop_policy(), WindowsProactorEventLoopPolicy):
    asyncio.set_event_loop_policy(WindowsSelectorEventLoopPolicy())

3. 检查Page对象的状态管理

如果PWPageOjectFactory.create_page_object()复用了同一个浏览器上下文或页面,测试间的状态残留可能导致挂起:

  • 确保每个测试后重置页面状态(如await page.goto("https://www.google.com")或await page.reload());
  • 若无需强复用,可将page fixture的scope改为function验证问题:
@pytest_asyncio.fixture(scope="function")
async def page(browser):
    factory = PWPageOjectFactory("https://www.google.com", browser)
    page = await factory.create_page_object()
    yield page
    await page.close()

4. 排查测试用例中的异步操作

test_navigate中的navigate_forward可能因页面无历史记录导致阻塞,添加前置导航生成历史:

@pytest.mark.asyncio
async def test_navigate(page):
    # 先导航到其他页面生成历史记录
    await page.goto("https://www.github.com")
    await page.goto("https://www.google.com")
    
    element = await page.get_active_element()
    await page.navigate_forward()
    new_element = await page.get_active_element()
    assert element.get_attribute("id") != new_element.get_attribute("id")
    await page.navigate_backward()
    new_element = await page.get_active_element()
    assert element.get_attribute("id") == new_element.get_attribute("id")

内容的提问来源于stack exchange,提问作者Jose Jorge Rodriguez Salgado

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.25 08:47:04