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

pytest自动会话级Fixture已发现未执行,环境变量设置失败求助

问题描述

我正在测试基于python-telegram-bot开发的机器人,使用pyrogram模拟输入。测试时需在环境中设置加密密钥,因此在conftest.py中编写了标注为@pytest.fixture(autouse=True, scope="session")的set_crypt_key Fixture来实现,但该Fixture虽被pytest识别,却未执行。

从根目录执行命令pytest -s --fixtures可看到该Fixture,但运行测试时,测试收集阶段就因找不到密钥TELOPS_CRYPT_KEY触发KeyError,且Fixture中的print内容未输出。

文件结构

--root
   |-tests/
       |- conftest.py
       |- test_something1.py
       |- test_something2.py

conftest.py 代码

# coding:utf-8
import os

import pytest
from pyrogram import Client
from telegram.ext import Application

from config import BOT_ID
from contrib.consts import CRYPT_KEY_EDK
from tests.config import TESTER_USERNAME, API_ID, API_HASH, CRYPT_KEY

@pytest.fixture
async def bot():
    async with Application.builder().token(BOT_ID).build() as bot:
        yield bot


@pytest.fixture
async def pyro_client():
    async with Client(name=TESTER_USERNAME, api_id=API_ID, api_hash=API_HASH) as pyro_client:
        yield pyro_client


@pytest.fixture(autouse=True, scope="session")
def set_crypt_key():
    print("Entered set_crypt_key fixture")
    os.environ[CRYPT_KEY_EDK] = CRYPT_KEY

测试文件 test_can_access_netbox.py 代码

# coding: utf-8
from unittest import mock

import pynetbox
import pytest
import requests
from pynetbox import RequestError
from telegram.ext import ContextTypes

from contrib.consts import NETBOX_CONFIG_CDK
from contrib.datawrappers.netboxconfig import NetboxConfig
from tests.config import NETBOX_TEST_TOKEN, NETBOX_TEST_URL

chat_data_mock = {
    NETBOX_CONFIG_CDK: NetboxConfig(token=NETBOX_TEST_TOKEN, url=NETBOX_TEST_URL)
}


@mock.patch("telegram.ext.ContextTypes.DEFAULT_TYPE", chat_data=chat_data_mock)
def test_can_access_netbox(context: ContextTypes.DEFAULT_TYPE):
    """TC002"""
    try:
        nb = pynetbox.api(**context.chat_data[NETBOX_CONFIG_CDK].to_dict())
        nb.status()
    except RequestError as e:
        pytest.fail("Error requesting connection to Netbox: {}".format(e))
    except requests.exceptions.ConnectionError as e:
        pytest.fail("Connection error: {}".format(e))

if __name__ == '__main__':
    test_can_access_netbox()

错误信息

------------------------------------------------------------- fixtures defined from tests.fixtures -------------------------------------------------------------
bot -- tests/fixtures.py:19
pyro_client -- tests/fixtures.py:29
set_crypt_key [session scope] -- tests/fixtures.py:39

============================================================================ ERRORS ============================================================================
_______________________________________________________ ERROR collecting tests/test_can_access_netbox.py _______________________________________________________
tests/test_can_access_netbox.py:16: in <module>
    NETBOX_CONFIG_CDK: NetboxConfig(token=NETBOX_TEST_TOKEN, url=NETBOX_TEST_URL)
contrib/datawrappers/netboxconfig.py:8: in __init__
    super().__init__()
contrib/classesbehaviors/cryptographs.py:13: in __init__
    self.crypt = Fernet(os.environ[CRYPT_KEY_EDK].encode())
/usr/lib/python3.8/os.py:675: in __getitem__
    raise KeyError(key) from None
E   KeyError: 'TELOPS_CRYPT_KEY'
=================================================================== short test summary info ====================================================================
ERROR tests/test_can_access_netbox.py - KeyError: 'TELOPS_CRYPT_KEY'
======================================================================= 1 error in 0.36s =======================================================================

使用的依赖版本

  • pytest==7.2.1
  • pytest-asyncio==0.20.3
  • Python 3.8.10

问题原因

核心问题在于测试执行顺序:pytest会先执行测试收集流程,此时会导入测试文件并执行模块级别的代码(比如chat_data_mock的定义),而NetboxConfig的实例化会触发父类初始化,直接读取环境变量中的密钥。但session级别的Fixture要在测试收集完成后才会执行,导致此时密钥还未设置,触发KeyError。

解决方法

方法1:调整mock数据的定义位置

把模块级别的chat_data_mock移到测试函数内部,确保在Fixture执行后再初始化NetboxConfig:

# coding: utf-8
from unittest import mock

import pynetbox
import pytest
import requests
from pynetbox import RequestError
from telegram.ext import ContextTypes

from contrib.consts import NETBOX_CONFIG_CDK
from contrib.datawrappers.netboxconfig import NetboxConfig
from tests.config import NETBOX_TEST_TOKEN, NETBOX_TEST_URL


def test_can_access_netbox():
    """TC002"""
    # 将mock数据移到函数内部,确保Fixture执行后再创建实例
    chat_data_mock = {
        NETBOX_CONFIG_CDK: NetboxConfig(token=NETBOX_TEST_TOKEN, url=NETBOX_TEST_URL)
    }
    with mock.patch("telegram.ext.ContextTypes.DEFAULT_TYPE", chat_data=chat_data_mock) as context:
        try:
            nb = pynetbox.api(**context.chat_data[NETBOX_CONFIG_CDK].to_dict())
            nb.status()
        except RequestError as e:
            pytest.fail("Error requesting connection to Netbox: {}".format(e))
        except requests.exceptions.ConnectionError as e:
            pytest.fail("Connection error: {}".format(e))

if __name__ == '__main__':
    test_can_access_netbox()

方法2:使用pytest钩子提前设置环境变量

在conftest.py中添加pytest_configure钩子,该钩子会在测试收集前执行,提前设置好环境变量:

def pytest_configure():
    import os
    from contrib.consts import CRYPT_KEY_EDK
    from tests.config import CRYPT_KEY
    os.environ[CRYPT_KEY_EDK] = CRYPT_KEY

内容的提问来源于stack exchange,提问作者João Pedro Martins de Paula

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.31 22:55:18