如何在不重复代码的情况下为多模块运行相同的Pytest测试?
问题描述
我有一个包含多个模块的项目,这些模块普遍需要同类测试。每个模块都会导入同名文件,基于该文件的测试逻辑完全相同。
当前测试代码示例:
# test/integration/app1_test.py from app1 import app def test_app(): response = app.get_response() assert response == True
app1、app2、app3的测试逻辑完全一致。我想避免在app1_test、app2_test、app3_test中重复编写相同代码,理想是通过继承类实现,比如:
test/conftest.py:
class TestApp: def __init__(self, App): # 希望能将其作为fixture传入 self.app = App def test_app(self): response = self.app.get_response() assert response == True
test/integration/app1_test.py:
from app1 import app @pytest.fixture(scope="module") def App(): return app
test/integration/app2_test.py:
from app2 import app from conftest import TestApp @pytest.fixture(scope="module") def App(): return app class TestApp2(TestApp): def test_app(self): response = self.app.get_response() assert response == False def test_another_response(self): response = self.app.get_another_response() assert response == True
我能实现最接近上述流程的方案是什么?
我试过把测试函数放在conftest.py中,但执行python3 -m pytest时这些函数不会运行;也试过编写函数在各测试模块中导入手动运行,但它们不会被识别为pytest测试,只是普通Python函数。我希望pytest能收集并为项目中的每个模块运行这些测试。
可行解决方案
方法1:参数化fixture+共享测试函数(最简洁)
不需要类继承,直接通过参数化批量生成测试:
- 在
test/conftest.py中定义参数化fixture和基础测试逻辑:
import pytest from app1 import app as app1 from app2 import app as app2 from app3 import app as app3 # 为每个模块的app实例生成参数,ids用于区分测试用例 @pytest.fixture(params=[app1, app2, app3], ids=["app1", "app2", "app3"]) def app(request): return request.param # 基础测试逻辑,会自动为每个app实例执行一次 def test_app_base_response(app): response = app.get_response() assert response == True
执行python3 -m pytest时,pytest会自动为app1、app2、app3各运行一次test_app_base_response,无需在每个测试文件重复编写代码。
方法2:类继承+fixture注入(贴合你的需求)
如果偏好类继承的方式,可以通过pytest的fixture注入实现:
- 在
test/conftest.py定义基础测试类:
class BaseTestApp: # 测试方法依赖名为app的fixture,由子类所在模块提供 def test_app_response(self, app): response = app.get_response() assert response == True
- 在各模块的测试文件中,定义本地app fixture并继承基础类:
# test/integration/app1_test.py from app1 import app from conftest import BaseTestApp import pytest @pytest.fixture(scope="module") def app(): return app class TestApp1(BaseTestApp): # 直接继承基础测试方法,pytest会自动收集执行 pass
# test/integration/app2_test.py from app2 import app from conftest import BaseTestApp import pytest @pytest.fixture(scope="module") def app(): return app class TestApp2(BaseTestApp): # 重写基础测试,覆盖原有断言逻辑 def test_app_response(self, app): response = app.get_response() assert response == False # 添加模块专属的测试方法 def test_another_response(self, app): response = app.get_another_response() assert response == True
这种方式下,每个测试文件只需定义本地的app fixture,继承基础类后,pytest会自动收集并执行所有测试方法(包括继承的和自定义的)。
注意事项
conftest.py是用来共享fixture和钩子函数的,不能直接存放测试用例,否则pytest不会收集执行。- pytest只会识别测试模块(命名含
test_)中,以test_开头的函数/方法,直接导入的普通函数不会被当作测试用例。
内容的提问来源于stack exchange,提问作者hnandi
相关产品推荐
相关产品推荐

