Pytest无法发现含urllib.parse.quote_plus的测试问题排查
问题原因分析
核心问题在于模块导入阶段的未处理异常导致pytest无法加载目标模块,进而无法发现测试用例:
- 你的
baserepository.py中,数据库连接逻辑(包括连接字符串解析、SqlAlchemy引擎初始化)是在模块级别执行的(而非类/方法内部)。 - 当注释掉
urllib.parse.quote_plus时,未转义的连接字符串(或未加载环境变量导致的空值)会触发SqlAlchemy初始化异常,导致整个模块导入失败。pytest在扫描测试时会跳过无法导入的模块,自然找不到其中的测试用例。 - 取消注释后,连接字符串被正确转义,模块能正常加载,pytest可以扫描到测试用例。
另外,由于commonmodules依赖API目录中的环境变量配置,直接在commonmodules目录下运行pytest时,环境变量未被加载,会加剧这个问题——即使没有转义问题,空连接字符串也会触发初始化异常。
解决方案
1. 延迟数据库初始化到运行时
将数据库连接逻辑移到类的方法内部,避免在模块导入阶段执行,确保模块能正常加载,pytest可以发现测试用例:
# baserepository.py import os import urllib.parse from sqlalchemy import create_engine class BaseRepository: def __init__(self): sql_conn_str = os.getenv("SQL_CONN_STR") if not sql_conn_str: raise ValueError("SQL_CONN_STR环境变量未设置") # 仅在实例化时解析连接字符串并创建引擎 encoded_conn_str = urllib.parse.quote_plus(sql_conn_str) self.engine = create_engine(f"mssql+pyodbc:///?odbc_connect={encoded_conn_str}")
2. 为测试提供独立的环境变量或Mock
在commonmodules目录下添加测试专用的环境变量配置,或Mock数据库连接逻辑,避免依赖API的环境配置:
方式一:添加测试.env文件
在commonmodules目录下创建.env文件,填入测试用的连接字符串:SQL_CONN_STR=你的测试数据库连接字符串然后在测试文件或
conftest.py中加载这个文件:# commonmodules/conftest.py from dotenv import load_dotenv from pathlib import Path load_dotenv(Path(__file__).parent / ".env")方式二:Mock数据库连接
在conftest.py中Mock SqlAlchemy的create_engine,跳过真实数据库连接:# commonmodules/conftest.py import pytest from unittest.mock import Mock, patch @pytest.fixture(autouse=True) def mock_db_engine(): with patch("baserepository.create_engine") as mock_engine: mock_engine.return_value = Mock() yield
3. 确保运行pytest时加载正确的环境变量
如果要从API目录运行pytest(扫描commonmodules的测试),需要加载API的本地环境配置。以Azure Functions的local.settings.json为例,可以用代码加载:
# commonmodules/conftest.py import os from pathlib import Path import json # 加载API1的local.settings.json api_settings_path = Path(__file__).parent.parent / "API1" / "local.settings.json" with open(api_settings_path, "r") as f: settings = json.load(f) for key, value in settings.get("Values", {}).items(): os.environ[key] = value
4. 模块级异常捕获(临时方案)
如果必须在模块级别处理连接字符串,添加异常捕获逻辑,确保模块能正常加载:
# baserepository.py import os import urllib.parse from sqlalchemy import create_engine sql_conn_str = os.getenv("SQL_CONN_STR") engine = None try: if sql_conn_str: encoded_conn_str = urllib.parse.quote_plus(sql_conn_str) engine = create_engine(f"mssql+pyodbc:///?odbc_connect={encoded_conn_str}") except Exception as e: print(f"数据库初始化失败:{str(e)}") # 不抛出异常,让模块继续加载
内容的提问来源于stack exchange,提问作者Shivani
相关产品推荐
相关产品推荐

