一、从踩坑说起:为啥测试总漏测场景

做测试的人大多遇到过这种情况:明明写了测试用例,跑的时候却没执行,或者该生效的测试配置没加载,最后上线出了问题才发现是测试环节漏了。我之前做一个电商后台的订单模块测试时,就踩过这个坑:当时为了测试不同支付场景的兼容性,写了好几组测试用例,结果跑测试时只有一半生效,排查了三天才发现,是我把测试文件的名字写错了,加上公共配置的加载顺序不对,导致测试框架根本没识别到那组用例。

后来我才明白,测试里的“漏测”很多不是用例没写,而是测试框架的“发现机制”出了问题——要么没找到测试文件,要么没加载对公共配置。而测试框架的发现机制,核心就藏在两个地方:测试文件的命名规则,还有公共配置文件(conftest)的加载顺序。

二、测试文件命名:别让框架“看不见”你的用例

很多测试框架找测试用例的逻辑很简单:看文件名。比如Python里的pytest,默认只认两种名字的文件:以test_开头的Python文件,或者以_test.py结尾的Python文件。如果你的测试文件不满足这个规则,框架就会把它当成普通业务代码,直接跳过。

2.1 命名规则的具体示例(技术栈:Python+pytest)

我拿之前踩坑的订单测试举例子,当时我写了三组测试用例,分别对应微信支付、支付宝、银联的场景,文件命名如下:

# 正确的命名(框架能识别)
test_wechat_payment.py  # 以test_开头
alipay_payment_test.py  # 以_test.py结尾

# 错误的命名(框架识别不到)
unionpay_payment.py     # 既不以test_开头,也不以_test.py结尾
test-unionpay-payment.py  # 用了横杠,pytest默认不支持(部分框架支持,但pytest不兼容)

当时我就是把银联的测试文件写成了unionpay_payment.py,结果pytest跑的时候直接没扫到,导致银联支付的场景完全没测,上线后才发现银联支付的订单状态更新有bug。

2.2 命名规则的扩展:自定义匹配逻辑

如果你的项目有特殊的命名习惯,比如所有测试文件都以tc_开头(test case的缩写),能不能让框架识别?当然可以,只要给pytest加个自定义的配置就行。比如在项目根目录的pytest.ini里加一行:

[pytest]
python_files = tc_*.py  # 把tc_开头的文件也当成测试文件

加了这个配置后,tc_unionpay_payment.py这样的文件就会被pytest识别为测试文件了。

三、conftest加载顺序:别让配置“晚到”拖后腿

除了测试文件的命名,公共配置的加载顺序也是个容易踩坑的点。这里说的公共配置,就是pytest里的conftest.py文件——它是pytest的公共配置文件,用来放测试夹具(fixture)、钩子函数这些公共内容。比如测试时需要的数据库连接、测试用的测试数据,都可以写在conftest里。

很多人以为conftest只有根目录有一个就行,其实pytest支持在任意目录下放conftest,而且不同位置的conftest加载顺序不一样,作用范围也不一样。如果加载顺序错了,就会出现“用例找不到配置”的问题。

3.1 加载顺序的具体规则(技术栈:Python+pytest)

我先拿一个实际的项目目录结构来说,这个结构是很多Python项目常用的:

my_project/  # 项目根目录
├── conftest.py  # 根目录的conftest
├── pytest.ini  # 测试配置文件
├── src/  # 业务代码目录
│   └── order.py  # 订单业务代码
└── tests/  # 测试目录
    ├── conftest.py  # tests目录的conftest
    ├── test_wechat_payment.py
    ├── alipay_payment_test.py
    └── unionpay/  # 银联测试子目录
        ├── conftest.py  # unionpay子目录的conftest
        └── test_unionpay_payment.py

pytest加载conftest的顺序是:从测试文件所在的目录开始,往上找父目录,直到根目录,每个目录下的conftest都会被加载,而且越靠近测试文件的conftest,优先级越高。具体到上面的结构,当运行tests/unionpay/test_unionpay_payment.py时,加载顺序是:

  1. 先加载tests/unionpay/conftest.py(最靠近测试文件)
  2. 再加载tests/conftest.py
  3. 最后加载my_project/conftest.py(最远离测试文件)

这个优先级很重要:如果不同目录的conftest里有同名的夹具,越靠近测试文件的会覆盖上层的。比如根目录的conftest里定义了一个夹具db_conn,用来连接测试数据库,而tests/unionpay/conftest里也定义了一个同名的db_conn,用来连接银联专属的测试数据库,那么运行银联的测试用例时,会用tests/unionpay/conftest里的db_conn,而不是根目录的。

3.2 加载顺序踩坑示例(技术栈:Python+pytest)

我之前还踩过一个加载顺序的坑:当时为了给所有测试用例加一个“测试前打印当前用例名称”的钩子函数,我把这个钩子写在了根目录的conftest里,代码如下:

# my_project/conftest.py(根目录的conftest)
import pytest

# 钩子函数:每个测试用例运行前执行
@pytest.hookimpl(hookwrapper=True)
def pytest_runtest_protocol(item, nextitem):
    # 打印当前测试用例的名称
    print(f"开始运行测试用例:{item.name}")
    yield
    print(f"结束运行测试用例:{item.name}")

结果运行的时候,只有根目录下的测试用例打印了名称,tests目录下的用例都没打印。后来排查才发现,tests目录下也有一个conftest,里面有一个同名的钩子函数,而且这个钩子函数里没有打印的逻辑,导致根目录的钩子被覆盖了。

解决方法很简单:要么把tests目录下的同名钩子删掉,要么给tests目录下的钩子加打印逻辑,要么把钩子函数移到tests目录的conftest里(如果只需要给tests目录的用例生效)。

四、应用场景与注意事项

4.1 应用场景

命名规则和加载顺序的知识点,在这些场景下特别有用:

  1. 大型项目的分层测试:比如项目有单元测试、集成测试、端到端测试,不同层级的测试文件需要不同的命名规则,比如单元测试用test_*.py,集成测试用integration_*.py,端到端测试用e2e_*.py,这时候就需要自定义pytest的命名规则。
  2. 多模块的独立测试:比如一个项目有订单、用户、商品三个模块,每个模块的测试需要不同的公共配置,比如订单模块需要连接订单数据库,用户模块需要连接用户数据库,这时候就可以在每个模块的测试目录下放自己的conftest,利用加载顺序的优先级,让每个模块的测试用自己的配置。
  3. 临时测试的快速调整:比如临时要测某个特殊场景,不想改全局配置,就可以在临时测试目录下放一个conftest,覆盖全局的配置,测试完删掉就行。

4.2 技术优缺点

优点

  1. 灵活:命名规则可以自定义,加载顺序可以通过目录结构控制,能适配各种项目的需求。
  2. 隔离性:不同目录的conftest可以隔离配置,避免全局配置被滥用,比如某个模块的特殊配置不会影响其他模块的测试。
  3. 维护性:把公共配置按目录拆分,每个目录的配置只负责当前目录的测试,后期维护的时候更容易找到问题。

缺点

  1. 容易踩坑:命名规则和加载顺序的逻辑比较隐蔽,很多人不了解,容易出现“测试文件不被识别”“配置不生效”的问题。
  2. 配置混乱:如果项目目录结构复杂,conftest太多,很容易出现同名配置互相覆盖的问题,排查起来很麻烦。

4.3 注意事项

  1. 命名规则要统一:不管是用默认规则还是自定义规则,项目里的测试文件命名要统一,比如要么都用test_*.py,要么都用*_test.py,不要混着用,避免混乱。
  2. 不要随意放conftest:conftest的作用范围是当前目录及其子目录,所以不要在不需要的目录下放conftest,比如业务代码目录(src)下就不要放conftest,避免配置被错误加载。
  3. 同名配置要注意优先级:如果不同目录的conftest里有同名的夹具或钩子,一定要明确哪个配置是需要的,避免上层配置被下层配置覆盖。
  4. 测试前先扫一遍测试文件:跑测试前,可以先运行pytest --collect-only命令,看看pytest到底识别到了哪些测试文件和用例,避免漏测。这个命令的作用是只收集测试用例,不运行,输出的结果里会列出所有被识别的测试文件和用例:
# 运行pytest,只收集测试用例,不执行
pytest --collect-only

五、文章总结

测试的漏测问题,很多时候不是用例写得不够,而是测试框架的发现机制没搞懂。测试文件的命名是框架识别用例的“通行证”,命名不对,用例就会被当成普通代码跳过;conftest的加载顺序是公共配置生效的“优先级规则”,顺序不对,配置就会被覆盖或者不生效。

搞懂这两个点,不仅能避免漏测,还能让测试配置更灵活、更易维护。不管是做单元测试还是集成测试,不管是小项目还是大型项目,这两个知识点都是测试环节的基础,也是很多人容易忽略的细节。

最后再给大家提个醒:跑测试前一定要用pytest --collect-only扫一遍,确认所有测试文件都被识别到了,确认公共配置的加载顺序是对的,这样才能保证测试的有效性,避免上线后出问题。