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

相关推荐
计算机学姐3 分钟前
基于python+django+vue的影视推荐系统
开发语言·vue.js·后端·python·mysql·django·intellij-idea
扎克begod26 分钟前
JAVA并发编程系列(9)CyclicBarrier循环屏障原理分析
java·开发语言·python
青灯文案127 分钟前
SpringBoot 项目统一 API 响应结果封装示例
java·spring boot·后端
Book_熬夜!1 小时前
Python基础(九)——正则表达式
python·正则表达式·php
LQS20201 小时前
基于Python实现一个浪漫烟花秀
开发语言·python
梅如你1 小时前
python批量对遥感影像进行归一化与数据清洗
开发语言·python
Python私教1 小时前
Python国产新 ORM 框架 fastzdp_sqlmodel 快速入门教程
java·数据库·python
Python私教1 小时前
Python ORM 框架 SQLModel 快速入门教程
android·java·python
微尘81 小时前
C语言存储类型 auto,register,static,extern
服务器·c语言·开发语言·c++·后端
weixin_419349791 小时前
Python pdf转换为html
python·pdf