如何Mock pytest.fixture装饰器?为conftest.py内的fixture编写单元测试
如何Mock pytest.fixture装饰器来测试conftest中的fixture?
要测试conftest.py里的pytest fixture,核心思路是在导入目标fixture函数之前,先mock掉pytest.fixture装饰器,让它失去原有的装饰器功能,把fixture变成普通函数来测试。这样我们就能直接调用函数,验证它的业务逻辑,不用依赖pytest的运行环境。
先看你的conftest.py代码:
# conftest.py import pytest @pytest.fixture(scope="session", autouse="True") def get_ip(dict_obj): """假设存在某些功能""" return dict_obj.get('ip') @pytest.fixture(scope="class") def get_server(create_obj): """假设存在某些功能""" pass
下面是对应的测试文件test_conftest.py的实现:
# test_conftest.py from unittest.mock import patch # 关键步骤:先mock pytest.fixture装饰器 # 这里用嵌套lambda兼容装饰器带参数的情况(比如scope、autouse) # 最终效果:不管装饰器传什么参数,都直接返回原函数本身 mock_fixture = patch('pytest.fixture', lambda *args, **kwargs: lambda func: func).start() # 必须在mock完成后再导入conftest里的函数,否则装饰器已经生效了 from conftest import get_ip class TestConftestTests: def test_get_ip_with_existing_ip(self): # 模拟依赖的dict_obj参数 test_dict = {'ip': '192.168.1.1'} # 像调用普通函数一样调用get_ip,验证返回值 assert get_ip(test_dict) == '192.168.1.1' def test_get_ip_without_ip(self): empty_dict = {} assert get_ip(empty_dict) is None
几个需要注意的点:
- mock时机必须早于导入:
pytest.fixture是装饰器,当你导入get_ip时,装饰器已经执行了。如果先导入再mock,就起不到效果了。 - 兼容带参数的装饰器:我们用
lambda *args, **kwargs: lambda func: func来处理装饰器的参数,不管@pytest.fixture传了scope还是autouse,最终都返回原函数,保证fixture能以普通函数的形式被调用。 - 测试依赖项:如果fixture依赖其他对象(比如
get_server依赖create_obj),测试时直接传入模拟的create_obj即可,和测试普通函数完全一样。
内容的提问来源于stack exchange,提问作者Hemant
相关产品推荐
相关产品推荐

