必须在conftest.py中定义pytest_addoption钩子注册参数,通过request.config.getoption()在测试函数或fixture中安全读取,且需设default值、避免顶层调用;参数类型校验推荐用choices限制合法值。

如何在pytest中注册自定义命令行参数
pytest允许通过pytest_addoption钩子函数注入新命令行选项,这是所有自定义参数的入口。必须把它放在conftest.py文件里(通常放在项目根目录或测试目录下),否则pytest启动时不会识别。
常见错误是把该函数写在普通.py测试文件里,或者忘了加parser.addoption()调用——此时运行pytest --help看不到你的参数,且request.config.getoption()会抛ValueError: no option named异常。
- 必须使用
conftest.py,不能是test_*.py或__init__.py -
addoption的dest参数决定后续获取时的键名,推荐与name一致(如--env对应dest="env") - 务必设
default值,否则未传参时getoption返回None,容易引发空值错误
# conftest.py
def pytest_addoption(parser):
parser.addoption(
"--env",
action="store",
default="staging",
type=str,
help="Run tests against specific environment: dev/staging/prod"
)
如何在测试函数中读取并使用自定义参数
参数值不能直接全局访问,必须通过request.config.getoption()从fixture中获取。最常用的是request fixture,它在每个测试函数作用域内可用。
注意:不要试图在模块顶层或setup_module里读取,因为pytest配置对象尚未初始化完成;也不要用sys.argv手动解析——这绕过了pytest的参数管理机制,会导致--help不显示、类型校验失效、与其他插件冲突。
立即学习“Python免费学习笔记(深入)”;
- 必须在测试函数签名中声明
requestfixture(哪怕只用一次) -
getoption()的参数名必须和addoption(dest=...)完全一致 - 若参数用于控制跳过逻辑,建议封装成独立fixture,避免每个测试都重复写
if request.config.getoption(...)
# test_api.py
def test_user_login(request):
env = request.config.getoption("--env")
if env == "prod":
pytest.skip("Skip login test in prod")
# ... actual test logic
如何基于自定义参数动态生成测试用例
当需要为不同环境跑不同数据集时,用pytest_generate_tests钩子比在每个测试里if/else更干净。它在参数化前执行,能根据命令行参数修改metafunc.parametrize的输入。
典型陷阱是误以为pytest_generate_tests能访问request fixture——它只能通过metafunc.config拿到配置,且必须在conftest.py中定义,不能分散在多个文件。
- 只对带特定参数名的测试函数生效(靠
metafunc.fixturenames判断) - 参数值需提前用
metafunc.config.getoption()取出,不能依赖其他fixture - 若同时用了
@pytest.mark.parametrize,钩子函数会覆盖它;二者不要混用
# conftest.py
def pytest_generate_tests(metafunc):
if "env_data" in metafunc.fixturenames:
env = metafunc.config.getoption("--env")
data_map = {
"dev": [{"host": "localhost", "port": 8000}],
"staging": [{"host": "staging.example.com", "port": 443}],
}
metafunc.parametrize("env_data", data_map.get(env, []))
为什么--env参数在pytest-xdist并发下仍安全
每个worker进程启动时都会完整加载conftest.py并执行pytest_addoption,所以--env会被正确传递到所有子进程中。你不需要额外处理进程间同步。
但要注意:如果在conftest.py里做了基于--env的全局状态修改(比如修改os.environ或单例类属性),这些修改只在当前worker内有效。跨worker共享状态仍是危险的,应避免。
-
pytest-xdist默认把命令行参数广播给所有worker,无需--tx额外指定 - 不要在
pytest_configure里缓存getoption结果到模块变量——worker间不共享内存 - 日志中看到不同worker打出不同
--env值,说明参数已正确分发
真正容易被忽略的是参数类型校验:比如--env期望字符串但用户输成了--env=123,pytest默认不会报错。如果业务逻辑强依赖枚举值,应在pytest_addoption里加choices=["dev","staging","prod"],或在fixture中做显式检查。


















