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

Selenium Pytest出现ValueError: setup未生成值的问题排查

问题:Pytest Class级Fixture抛出ValueError: setup did not yield a value的原因与修复方案

问题背景

我有多个基于Selenium+Python+Pytest的测试套件(如test_invoice.py、test_admin.py等),均使用同一个class级别的setup fixture。通过Docker执行测试的命令如下:

python -m pytest -v -s --capture=tee-sys --html=report.html --self-contained-html test_invoice.py test_admin.py test_cash.py

setup fixture代码如下:

@pytest.fixture(scope='class')
def setup(request):
  try:
    options = webdriver.ChromeOptions()
    options.add_argument("--window-size=1920,1080")
    options.add_argument("--start-maximized")
    options.add_argument('--headless')
    options.add_argument('--ignore-certificate-errors')
    driver = webdriver.Chrome(options=options)
    request.cls.driver = driver
    driver.delete_all_cookies()
    driver.get(TestData_common.BASE_URL)
    yield
    driver.quit()
except WebDriverException as e:
    print('App seems to be down...> ', e)


@pytest.mark.usefixtures("setup")
@pytest.mark.incremental
class Test_app:
  def test_001_login(self):
    assert TestData_common.URL_FOUND, "UAT seems to be down.."
    self.loginPage = LoginPage(self.driver)
    self.loginPage.do_click_agree_button()
    assert TestData_common.AGREE_BTN_FOUND, "Unable to click AGREE button.."
    self.driver.maximize_window()
    print('Successfully clicked AGREE button')
    time.sleep(2)

测试过程中偶尔会抛出如下错误:

request = <SubRequest 'setup' for <Function test_001_login>>
kwargs = {'request': <SubRequest 'setup' for <Function test_001_login>>}

def call_fixture_func(
    fixturefunc: "_FixtureFunc[FixtureValue]", request: FixtureRequest, kwargs
) -> FixtureValue:
    if is_generator(fixturefunc):
        fixturefunc = cast(
            Callable[..., Generator[FixtureValue, None, None]], fixturefunc
        )
        generator = fixturefunc(**kwargs)
        try:
            fixture_result = next(generator)
        except StopIteration:
>               raise ValueError(f"{request.fixturename} did not yield a value") from None
E               **ValueError: setup did not yield a value**

原因分析

这个错误的核心是fixture的try/except代码块范围错误:

  • 你把yield和driver.quit()都放在了try块内,而except块直接跟在try外部。
  • 当try块内的代码(如Chrome初始化、页面访问)抛出WebDriverException时,程序会直接跳转到except块执行打印逻辑,随后函数直接结束,完全没走到yield语句。
  • Pytest的生成器类型fixture要求必须执行到yield,否则会被判定为“未产生值”,进而抛出ValueError。

修复方案

调整try/except的范围,确保无论是否发生异常,yield都会被执行,同时正确清理资源:

修复后的fixture代码

@pytest.fixture(scope='class')
def setup(request):
    driver = None
    try:
        options = webdriver.ChromeOptions()
        options.add_argument("--window-size=1920,1080")
        options.add_argument("--start-maximized")
        options.add_argument('--headless')
        options.add_argument('--ignore-certificate-errors')
        driver = webdriver.Chrome(options=options)
        request.cls.driver = driver
        driver.delete_all_cookies()
        driver.get(TestData_common.BASE_URL)
        yield  # 确保此语句一定会被执行
    except WebDriverException as e:
        print('App seems to be down...> ', e)
        # 可选:重新抛出异常,让测试直接标记为失败
        raise
    finally:
        # 无论是否异常,都关闭浏览器,避免资源泄漏
        if driver is not None:
            driver.quit()

关键修改点

  1. 预初始化driver为None:避免finally块引用未定义的变量
  2. 缩小try块范围:仅将可能抛出WebDriverException的初始化代码放在try内,yield放在try块末尾
  3. 用finally块清理资源:不管是否发生异常,都会执行浏览器关闭逻辑,防止进程残留
  4. 可选重新抛出异常:如果希望fixture异常时直接终止测试,可在except块中添加raise,否则测试会继续执行,可能引发更多错误

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.26 12:01:29