深入探索pytest-mock插件:简化Python单元测试中的模拟和替换

前言

进行接口测试时,可能有些接口逻辑未实现或者不满足要求,我们需要先调试case的逻辑,此时可能就需要mock了。那在pytest中该如何进行mock呢?带着这个疑问我们一起探索。

pytest-mock是啥?

pytest-mock是一个pytest的插件,安装即可使用。它提供了一个名为mocker的fixture,仅在当前测试function或method生效,而不用自行包装。

首先,我们需要安装pytest-mock库。可以使用pip命令来安装:

复制代码
pip install pytest-mock

基本用法

模拟函数的返回值

有时我们需要模拟一个函数的返回值,以便更好地控制测试场景。pytest-mock可以通过mocker夹具实现这一点。以下是一个示例:

ini 复制代码
# 测试函数
def test_function(mocker):
    # 模拟一个函数的返回值
    mocker.patch('module.function', return_value=42)
    
    result = module.function()
    
    assert result == 42

在上面的示例中,我们使用mocker.patch方法模拟了module.function函数的返回值为42。然后,我们调用该函数,并断言返回的结果是否为42。

模拟函数的行为

有时我们需要模拟一个函数的行为,例如抛出异常或调用其他函数。pytest-mock提供了side_effect参数来实现这一点。以下是一个示例:

scss 复制代码
# 测试函数
def test_function(mocker):
    # 模拟一个函数的行为,抛出异常
    mocker.patch('module.function', side_effect=Exception('mocked error'))
    
    with pytest.raises(Exception):
        module.function()

在上面的示例中,我们使用mocker.patch方法模拟了module.function函数抛出异常。然后,我们使用pytest.raises上下文管理器来捕获预期的异常。

模拟对象的属性

除了模拟函数的返回值和行为,pytest-mock还可以模拟对象的属性。以下是一个示例:

ini 复制代码
# 测试函数
def test_function(mocker):
    # 创建一个模拟对象
    obj = mocker.MagicMock()
    # 设置模拟对象的属性
    obj.attribute = 10
    
    assert obj.attribute == 10

在上面的示例中,我们使用mocker.MagicMock创建了一个模拟对象,并通过设置obj.attribute属性为10来模拟对象的属性。然后,我们断言该属性的值是否为10。

场景案例

一个简单的计算器类Calculator,该类提供了加法和乘法运算的方法。我们将使用pytest-mock来模拟依赖项并针对这个模块编写单元测试。

test_demo.py

python 复制代码
class Calculator:
    def add(self, x, y):
        pass
​
    def multiply(self, x, y):
        pass
​
​
# 测试计算器类的加法运算
def test_addition(mocker):
    # 创建一个模拟对象
    calculator = Calculator()
​
    # 模拟add方法的行为
    mocker.patch.object(calculator, 'add', return_value=5)
​
    # 调用add方法
    result = calculator.add(2, 3)
​
    # 断言结果是否为模拟的返回值
    assert result == 5
​
​
# 测试计算器类的乘法运算
def test_multiplication(mocker):
    # 创建一个模拟对象
    calculator = Calculator()
​
    # 模拟multiply方法的行为
    mocker.patch.object(calculator, 'multiply', side_effect=lambda x, y: x * y)
​
    # 调用multiply方法
    result = calculator.multiply(2, 3)
​
    # 断言结果是否为模拟的返回值
    assert result == 6
​

在上述代码中,我们定义了两个测试函数test_additiontest_multiplication,分别测试了计算器类的加法运算和乘法运算。

对于测试加法运算的函数test_addition,我们创建了一个名为calculator的模拟对象,并使用mocker.patch.object方法模拟了calculator.add方法的返回值为5。然后,我们调用calculator.add(2, 3)进行加法运算,并使用断言验证结果是否为模拟的返回值。

对于测试乘法运算的函数test_multiplication,我们也创建了一个名为calculator的模拟对象,并使用mocker.patch.object方法模拟了calculator.multiply方法的行为,即通过lambda函数实现了真实的乘法运算。然后,我们调用calculator.multiply(2, 3)进行乘法运算,并使用断言验证结果是否正确。

运行测试: 执行以下命令来运行测试:

arduino 复制代码
pytest -s -v test_demo.py::test_addition

执行之后会输出PASSED,我们如果改动mock值mocker.patch.object(calculator, 'add', return_value=51),再次执行命令,会输出如下结果:

markdown 复制代码
FAILED
​
=============================================================== FAILURES ===============================================================
____________________________________________________________ test_addition _____________________________________________________________
​
mocker = <pytest_mock.plugin.MockerFixture object at 0x11140a250>
​
    def test_addition(mocker):
        # 创建一个模拟对象
        calculator = Calculator()
​
        # 模拟add方法的行为
        mocker.patch.object(calculator, 'add', return_value=51)
​
        # 调用add方法
        result = calculator.add(2, 3)
​
        # 断言结果是否为模拟的返回值
>       assert result == 5
E       assert 51 == 5
​
test_dir/test_demo.py:24: AssertionError

相信到这里你应该已经掌握的它的用法。

运行机制

pytest-mock的运行机制如下:

  1. pytest-mock的mock功能,可以用来修改、替换或者移除原有的Python对象。
  2. 在测试函数中,如果需要mock某个函数或对象的行为,可以在测试函数参数中添加mocker参数,mocker是一个Fixture对象,可以用来创建并管理mock对象。
  3. 通过调用mocker.patch()方法,可以对要mock的函数或对象进行替换或者修改。例如,在测试函数中,调用mocker.patch()方法,并传入要mock的函数名以及mock后的返回值,就可以将该函数的实际调用结果替换成mock的返回值,以便测试函数的正确性。

最后

本文介绍了pytest-mock的基本用法,包括模拟函数的返回值和行为,以及模拟对象的属性。我们还通过一个案例说明展示了如何使用pytest-mock进行单元测试。掌握了这些基本用法,可以更轻松地编写可靠的单元测试。

相关推荐
geovindu7 小时前
CSharp: Wordcloud
开发语言·后端·c#·.net·.netcore·词云
智购科技自动售卖机厂家7 小时前
2026自动售货机库存热力图分析:从设备分布到补货优先级的数据可视化实践~YH
大数据·python·信息可视化
鹿鹿学长7 小时前
微软把语音转写打到 0.1 美元/小时:5 个月降价 72%,AI 音频进入地板价时代
python·自动化
weixin_440730507 小时前
使用pytest中方法控制执行步骤(test_begin.py、test_end.py,@pytest.mark.run(order=1))
开发语言·python·pytest
小柯南敲键盘7 小时前
跨境电商批量图片翻译与视频字幕翻译,就用跨马AI工具
大数据·人工智能·python·音视频
geovindu8 小时前
CSharp: Command Pattern
开发语言·后端·c#·.net·.netcore·命令模式·行为模式
心易行者8 小时前
Python自动化测试7步落地法:用python在线运行省掉90%环境配置时间
java·开发语言·人工智能·python·log4j·ai编程
Boop_wu8 小时前
[LangGraph] 案例 2 : 支持搜索的智能代理系统
服务器·windows·python·langchain
2601_962297259 小时前
Python、Pytest、Allure、Selenium和Jenkins实现自动化测试集成实例
python·selenium·jenkins·pytest·allure
tedcloud1239 小时前
OpenLogi 怎么搭建?用 Rust 打造一个轻量的 Logitech 外设管理工具
linux·运维·服务器·开发语言·后端·rust·开源