深入探索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进行单元测试。掌握了这些基本用法,可以更轻松地编写可靠的单元测试。

相关推荐
leobertlan5 小时前
2025年终总结
前端·后端·程序员
面向Google编程6 小时前
从零学习Kafka:数据存储
后端·kafka
冷雨夜中漫步6 小时前
Python快速入门(6)——for/if/while语句
开发语言·经验分享·笔记·python
郝学胜-神的一滴6 小时前
深入解析Python字典的继承关系:从abc模块看设计之美
网络·数据结构·python·程序人生
百锦再6 小时前
Reactive编程入门:Project Reactor 深度指南
前端·javascript·python·react.js·django·前端框架·reactjs
易安说AI7 小时前
Claude Opus 4.6 凌晨发布,我体验了一整晚,说说真实感受。
后端
易安说AI7 小时前
Ralph Loop 让Claude无止尽干活的牛马...
前端·后端
易安说AI7 小时前
用 Claude Code 远程分析生产日志,追踪 Claude Max 账户被封原因
后端
颜酱8 小时前
图结构完全解析:从基础概念到遍历实现
javascript·后端·算法
喵手8 小时前
Python爬虫实战:旅游数据采集实战 - 携程&去哪儿酒店机票价格监控完整方案(附CSV导出 + SQLite持久化存储)!
爬虫·python·爬虫实战·零基础python爬虫教学·采集结果csv导出·旅游数据采集·携程/去哪儿酒店机票价格监控