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
相关产品推荐
相关产品推荐

