0
点赞
收藏
分享

微信扫一扫

Pytest----Pytest自动化测试框架中猴子补丁的使用方法

一、猴子补丁简介

在有些场景下的测试可能需要修改全局配置或者系统变量等操作,而这些操作仅仅是为了做一些测试,不希望永久的修改,此时就需要使用猴子补丁了,猴子补丁,即monkeypatch,是一个fixture,它提供了以下方法:

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属性并不会真的发生修改

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属性并没有发生修改

$ 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中编写如下代码即可

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代码如下:

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()

执行结果如下:

$ 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继续优化如下:

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()

执行结果如下:

$ 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为被测函数,测试当被测字典被修改或者被删除时的情况

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()

执行结果如下:

$ 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进行优化,如下:

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()

执行结果如下:

$ 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 ===========================================================================


举报

相关推荐

0 条评论