测试开发技术网站
博客
设计
设计
开发
Python
测试
unittest
运维
Linux基础应用
CI/CD
CI/CD
数据库
数据库
云计算
云计算
云原生
云原生
爬虫
爬虫
数据分析
数据分析
人工智能
人工智能
登录
注册
Pytest----Pytest如何使用猴子补丁
收藏本文
作者:redrose2100 类别: 日期:2022-05-13 16:45:02 阅读:1056 次 消耗积分:0 分
[TOC] ![](https://redrose2100.oss-cn-hangzhou.aliyuncs.com/img/7cd47362-951c-11ee-986a-0242ac110004.png) ## 一、猴子补丁简介 在有些场景下的测试可能需要修改全局配置或者系统变量等操作,而这些操作仅仅是为了做一些测试,不希望永久的修改,此时就需要使用猴子补丁了,猴子补丁,即monkeypatch,是一个fixture,它提供了以下方法: ```bash monkeypatch.setattr(obj, name, value, raising=True) monkeypatch.setattr("somemodule.obj.name", value, raising=True) monkeypatch.delattr(obj, name, raising=True) monkeypatch.setitem(mapping, name, value) monkeypatch.delitem(obj, name, raising=True) monkeypatch.setenv(name, value, prepend=None) monkeypatch.delenv(name, raising=True) monkeypatch.syspath_prepend(path) monkeypatch.chdir(path) ``` 当测试结束后或者fixture执行完成后,monkeypatch中做的所有修改都将恢复 ## 二、通过猴子补丁临时修改函数功能 如下,可以通过猴子补丁修改Path的home属性,进而临时修改函数的功能,然后进行测试,这样测试结束后,Path的home属性并不会真的发生修改 ```python from pathlib import Path def getssh(): return Path.home() / ".ssh" def test_getssh(monkeypatch): def mockreturn(): return Path("/abc") monkeypatch.setattr(Path, "home", mockreturn) x = getssh() assert x == Path("/abc/.ssh") def test_home(): print(Path.home()) ``` 执行结果如下,很明显,在test_home测试函数中,Path.home属性并没有发生修改 ```bash $ pytest -s -v ========================================================================= test session starts ========================================================================== platform win32 -- Python 3.9.7, pytest-6.2.5, py-1.10.0, pluggy-1.0.0 -- D:\Python39\python.exe cachedir: .pytest_cache hypothesis profile 'default' -> database=DirectoryBasedExampleDatabase('D:\\src\\blog\\tests\\.hypothesis\\examples') rootdir: D:\src\blog\tests, configfile: pytest.ini plugins: allure-pytest-2.9.43, caterpillar-pytest-0.0.2, hypothesis-6.31.6, forked-1.3.0, rerunfailures-10.1, xdist-2.3.0 collected 2 items test_demo.py::test_getssh PASSED test_demo.py::test_home C:\Users\hitre PASSED ========================================================================== 2 passed in 0.13s =========================================================================== ``` ## 三、通过猴子补丁取消测试函数中request的使用 在conftest.py中编写如下代码即可 ```python import pytest @pytest.fixture(autouse=True) def no_requests(monkeypatch): """Remove requests.sessions.Session.request for all tests.""" monkeypatch.delattr("requests.sessions.Session.request") ``` ## 四、通过猴子补丁对环境变量测测试 如下,假设get_os_user_lower函数为被测函数,用例中可以通过猴子补丁对变量进行临时设置或删除,这样可以保证测试用例的准确性,否则当环境变量被修改或者被删除后,用例的稳定性将会收到影响 test_demo.py代码如下: ```python import os import pytest def get_os_user_lower(): username = os.getenv("USER") if username is None: raise OSError("USER environment is not set.") return username.lower() def test_upper_to_lower(monkeypatch): monkeypatch.setenv("USER", "TestingUser") assert get_os_user_lower() == "testinguser" def test_raise_exception(monkeypatch): monkeypatch.delenv("USER", raising=False) with pytest.raises(OSError): _ = get_os_user_lower() ``` 执行结果如下: ```bash $ pytest -v ========================================================================= test session starts ========================================================================== platform win32 -- Python 3.9.7, pytest-6.2.5, py-1.10.0, pluggy-1.0.0 -- D:\Python39\python.exe cachedir: .pytest_cache hypothesis profile 'default' -> database=DirectoryBasedExampleDatabase('D:\\src\\blog\\tests\\.hypothesis\\examples') rootdir: D:\src\blog\tests, configfile: pytest.ini plugins: allure-pytest-2.9.43, caterpillar-pytest-0.0.2, hypothesis-6.31.6, forked-1.3.0, rerunfailures-10.1, xdist-2.3.0 collected 2 items test_demo.py::test_upper_to_lower PASSED [ 50%] test_demo.py::test_raise_exception PASSED [100%] ========================================================================== 2 passed in 0.13s =========================================================================== ``` 上述代码可以通过fixture继续优化如下: ```python import os import pytest def get_os_user_lower(): username = os.getenv("USER") if username is None: raise OSError("USER environment is not set.") return username.lower() @pytest.fixture def mock_env_user(monkeypatch): monkeypatch.setenv("USER", "TestingUser") @pytest.fixture def mock_env_missing(monkeypatch): monkeypatch.delenv("USER", raising=False) def test_upper_to_lower(mock_env_user): assert get_os_user_lower() == "testinguser" def test_raise_exception(mock_env_missing): with pytest.raises(OSError): _ = get_os_user_lower() ``` 执行结果如下: ```bash $ pytest -v ========================================================================= test session starts ========================================================================== platform win32 -- Python 3.9.7, pytest-6.2.5, py-1.10.0, pluggy-1.0.0 -- D:\Python39\python.exe cachedir: .pytest_cache hypothesis profile 'default' -> database=DirectoryBasedExampleDatabase('D:\\src\\blog\\tests\\.hypothesis\\examples') rootdir: D:\src\blog\tests, configfile: pytest.ini plugins: allure-pytest-2.9.43, caterpillar-pytest-0.0.2, hypothesis-6.31.6, forked-1.3.0, rerunfailures-10.1, xdist-2.3.0 collected 2 items test_demo.py::test_upper_to_lower PASSED [ 50%] test_demo.py::test_raise_exception PASSED [100%] ========================================================================== 2 passed in 0.13s =========================================================================== ``` ## 五、通过猴子补丁对字典数据模拟测试 test_demo.py代码如下,其中DEFAULT_CONFIG为被测字典,create_connection_string为被测函数,测试当被测字典被修改或者被删除时的情况 ```python import pytest DEFAULT_CONFIG = {"user": "user1", "database": "db1"} def create_connection_string(config=None): config = config or DEFAULT_CONFIG return f"User Id={config['user']}; Location={config['database']};" def test_connection(monkeypatch): monkeypatch.setitem(DEFAULT_CONFIG, "user", "test_user") monkeypatch.setitem(DEFAULT_CONFIG, "database", "test_db") expected = "User Id=test_user; Location=test_db;" result = create_connection_string() assert result == expected def test_missing_user(monkeypatch): monkeypatch.delitem(DEFAULT_CONFIG, "user", raising=False) with pytest.raises(KeyError): _ = create_connection_string() ``` 执行结果如下: ```bash $ pytest -v ========================================================================= test session starts ========================================================================== platform win32 -- Python 3.9.7, pytest-6.2.5, py-1.10.0, pluggy-1.0.0 -- D:\Python39\python.exe cachedir: .pytest_cache hypothesis profile 'default' -> database=DirectoryBasedExampleDatabase('D:\\src\\blog\\tests\\.hypothesis\\examples') rootdir: D:\src\blog\tests, configfile: pytest.ini plugins: allure-pytest-2.9.43, caterpillar-pytest-0.0.2, hypothesis-6.31.6, forked-1.3.0, rerunfailures-10.1, xdist-2.3.0 collected 2 items test_demo.py::test_connection PASSED [ 50%] test_demo.py::test_missing_user PASSED [100%] ========================================================================== 2 passed in 0.13s =========================================================================== ``` 上述代码可以通过fixture进行优化,如下: ```python import pytest DEFAULT_CONFIG = {"user": "user1", "database": "db1"} def create_connection_string(config=None): config = config or DEFAULT_CONFIG return f"User Id={config['user']}; Location={config['database']};" @pytest.fixture def mock_test_user(monkeypatch): monkeypatch.setitem(DEFAULT_CONFIG, "user", "test_user") @pytest.fixture def mock_test_database(monkeypatch): monkeypatch.setitem(DEFAULT_CONFIG, "database", "test_db") @pytest.fixture def mock_missing_default_user(monkeypatch): monkeypatch.delitem(DEFAULT_CONFIG, "user", raising=False) def test_connection(mock_test_user, mock_test_database): expected = "User Id=test_user; Location=test_db;" result = create_connection_string() assert result == expected def test_missing_user(mock_missing_default_user): with pytest.raises(KeyError): _ = create_connection_string() ``` 执行结果如下: ```bash $ pytest -v ========================================================================= test session starts ========================================================================== platform win32 -- Python 3.9.7, pytest-6.2.5, py-1.10.0, pluggy-1.0.0 -- D:\Python39\python.exe cachedir: .pytest_cache hypothesis profile 'default' -> database=DirectoryBasedExampleDatabase('D:\\src\\blog\\tests\\.hypothesis\\examples') rootdir: D:\src\blog\tests, configfile: pytest.ini plugins: allure-pytest-2.9.43, caterpillar-pytest-0.0.2, hypothesis-6.31.6, forked-1.3.0, rerunfailures-10.1, xdist-2.3.0 collected 2 items test_demo.py::test_connection PASSED [ 50%] test_demo.py::test_missing_user PASSED [100%] ========================================================================== 2 passed in 0.12s =========================================================================== ```
始终坚持开源开放共享精神,同时感谢您的充电鼓励和支持!
版权所有,转载本站文章请注明出处:redrose2100, http://blog.redrose2100.com/article/186
上一篇:
Pytest----Pytest如何使用临时目录和文件
下一篇:
Pytest----Pytest如何执行文本测试
搜索
个人成就
出版书籍
《Pytest企业级应用实战》
测试开发技术全栈公众号
测试开发技术全栈公众号
DevOps技术交流微信群
加微信邀请进群
常用网站链接
开源软件洞察
云原生技术栈全景图
Python语言官方文档
Golang官方文档
Docker官方文档
Jenkins中文用户手册
Scrapy官方文档
VUE官方文档
Harbor官方文档
openQA官方文档
云原生开源社区
开源中国
Kubernetes中文文档
Markdown语法官方教程
Kubernetes中文社区
Kubersphere官方文档
BootStrap中文网站
JavaScript中文网
NumPy官方文档
Pandas官方文档
GitLink确实开源网站
数据库排名网站
编程语言排名网站
SEO综合查询网站
数学加减法练习自动生成网站
Kickstart Generator
文章分类
最新文章
最多阅读
特别推荐
×
Close
登录
注册
找回密码
登录邮箱:
登录密码:
图片验证码:
注册邮箱:
注册密码:
邮箱验证码:
发送邮件
注册邮箱:
新的密码:
邮箱验证码:
发送邮件