Python中另一个函数调用的模拟补丁一个函数
每当我们编写健壮的代码时,单元测试都是必不可少的。 他们帮助我们验证我们的应用程序逻辑并检查代码要求的所有其他方面; 然而,复杂性和外部依赖性等障碍使得编写高质量的测试用例变得困难。
在这一点上,Python 模拟库 unittest.mock 帮助我们克服了这些障碍。 今天,我们将了解模拟对象及其重要性,以及使用 Python patch()
的各种示例代码,这些示例代码将暂时用模拟对象替换目标。
模拟对象及其重要性
模拟对象以受控方式模仿真实对象的行为,例如,在测试环境中,我们执行不同的测试以确保代码按预期工作。 使用mock对象的过程称为Mocking; 它是提高测试质量的强大工具。
现在,重点是,为什么我们必须经历模拟? 使用它的根本原因是什么?
各种原因表明在 Python 中使用模拟的重要性。 让我们在下面看看它们:
- 一个主要原因是通过使用模拟对象来改进代码的行为。 例如,我们可以使用它们来测试 HTTP 请求(客户端向位于服务器上的指定主机发出的请求)并确保它们是否会导致间歇性故障。
- 我们可以用模拟对象替换实际的 HTTP 请求,这使我们能够以可预测的方式伪造外部服务中断和完全成功的响应。
- 当难以测试 if 语句和 except 块时,模拟也很有用。 使用模拟对象,我们可以控制代码的执行流程以到达这些区域(if 和 except)并提高代码覆盖率。
- 增加使用 Python 模拟对象重要性的另一个原因是正确理解我们如何在代码中使用它们的对应物。
Python Patch() 及其使用
unittest.mock 是 Python 中的 mock 对象库,它有一个 patch()
可以临时用 mock 对象替换 target。 在这里,目标可以是类、方法或函数。
要使用补丁,我们需要了解如何识别目标并调用 patch()
函数。
要识别目标,请确保目标是可导入的,然后在使用它的地方修补目标,而不是它来自的地方。 我们可以通过三种方式调用 patch()
; 作为类/函数的装饰器、上下文管理器或手动启动/停止。
当我们使用 patch()
作为类/函数的装饰器或在 with 语句内的上下文管理器中使用 patch()
时,目标将替换为新对象。 在这两种情况下,当 with 语句或函数存在时,补丁就会被撤消。
让我们创建一个启动代码并将其保存在 addition.py 文件中,我们将导入该文件以使用 patch()
作为装饰器、上下文管理器和手动启动/停止。
启动示例代码(保存在addition.py文件中):
def read_file(filename):
with open(filename) as file:
lines = file.readlines()
return [float(line.strip()) for line in lines]
def calculate_sum(filename):
numbers = read_file(filename)
return sum(numbers)
filename = "./test.txt"
calculate_sum(filename)
test.txt内容:
1
2
3
read_file()
获取文件名来读取行并将每一行转换为 float 类型。 它返回这些转换后数字的列表,我们将其保存在 calculate_sum()
函数内的 numbers 变量中。
现在,calculate_sum()
对数字列表中的所有数字求和并将其作为输出返回,如下所示:
输出:
6.0
使用 patch() 作为装饰器
让我们一步一步地学习 patch() 作为装饰器的用法。 完整的源代码在所有步骤的最后给出。
-
导入库和模块。
import unittest from unittest.mock import patch import addition
-
装饰
test_calculate_sum()
方法。@patch('addition.read_file') def test_calculate_sum(self, mock_read_file): #....
由于使用 @patch 装饰器,test_calculate_sum() 有一个额外的参数 mock_read_file。 这个附加参数是 MagicMock 的一个实例(我们可以将 mock_read_file 重命名为我们想要的任何名称)。
在 test_calculate_sum() 内部,patch() 将 addition.read_file() 函数替换为 mock_read_file 对象。
-
将列表分配给 mock_read_file.return_value。
mock_read_file.return_value = [1, 2, 3]
-
调用 calculate_sum() 并测试它。
result = addition.calculate_sum('') self.assertEqual(result, 6.0)
现在,我们可以调用
calculate_sum()
并使用assertEqual()
来测试总和是否为 6.0。在这里,我们可以将任何文件名传递给
calculate_sum()
函数,因为将调用 mock_read_file 对象而不是addition.read_file()
函数。 -
这是完整的源代码。
示例代码(保存在 test_sum_patch_decorator.py 文件中)
```python import unittest from unittest.mock import patch import addition
class TestSum(unittest.TestCase): @patch('addition.read_file') def test_calculate_sum(self, mock_read_file): mock_read_file.return_value = [1, 2, 3] result = addition.calculate_sum('') self.assertEqual(result, 6.0)
运行测试
```bash
python -m unittest test_sum_patch_decorator -v
使用上述命令运行测试以获得以下输出。
输出:
test_calculate_sum (test_sum_patch_decorator.TestSum) ... ok
----------------------------------------------------------------------
Ran 1 test in 0.001s
OK
使用 patch() 作为上下文管理器
示例代码(保存在 test_sum_patch_context_manager.py 文件中):
import unittest
from unittest.mock import patch
import addition
class TestSum(unittest.TestCase):
def test_calculate_sum(self):
with patch('addition.read_file') as mock_read_file:
mock_read_file.return_value = [1, 2, 3]
result = addition.calculate_sum('')
self.assertEqual(result, 6)
这段代码类似于我们使用 patch() 作为装饰器的最后一个代码示例,除了这里讨论的一些差异。
现在,我们没有 @patch('addition.read_file')
代码行,而 test_calculate_sum()
仅采用 self 参数(这是默认参数)。
with patch('addition.read_file') as mock_read_file
表示在上下文管理器中使用 mock_read_file 对象修补 addition.read_file() 。
简单来说,我们可以说 patch()
将替换 with 块中的 addition.read_file()
和 mock_read_file 对象。
现在,使用下面的命令运行测试。
python -m unittest test_sum_patch_context_manager -v
输出:
test_calculate_sum (test_sum_patch_context_manager.TestSum) ... ok
----------------------------------------------------------------------
Ran 1 test in 0.001s
OK
使用 patch() 手动启动/停止
示例代码(保存在 test_sum_patch_manually.py 文件中):
import unittest
from unittest.mock import patch
import addition
class TestSum(unittest.TestCase):
def test_calculate_sum(self):
patcher = patch('addition.read_file')
mock_read_file = patcher.start()
mock_read_file.return_value = [1, 2, 3]
result = addition.calculate_sum('')
self.assertEqual(result, 6.0)
patcher.stop()
此代码栅栏与前两个代码示例的作用相同,但在这里,我们手动使用 patch()
。 如何? 下面就来了解一下吧。
首先,我们导入所需的库。 在 test_calculate_sum()
内部,我们调用 patch()
以使用加法模块的目标 read_file()
函数启动补丁。
然后,我们为 read_file()
函数创建一个模拟对象。 之后,将数字列表分配给 mock_read_file.return_value,调用 calculate_sum()
并使用 assertEqual()
测试结果。
最后,我们通过调用修补程序对象的 stop()
方法停止修补。 现在,运行以下命令进行测试。
python -m unittest test_sum_patch_manually -v
输出:
test_calculate_sum (test_sum_patch_manually.TestSum) ... ok
----------------------------------------------------------------------
Ran 1 test in 0.001s
OK
相关文章
Python 四舍五入到最接近的十位
发布时间:2023/06/16 浏览次数:124 分类:Python
-
本篇文章将讨论使用 Python 的 ceil() 函数将数字四舍五入到最接近的十。Python 整数到最接近的十 Python 具有三个内置函数 round()、floor() 和 ceil(),可用于对数字进行舍入。
Python 中的模拟函数
发布时间:2023/06/16 浏览次数:127 分类:Python
-
Mock 是为与 unittest 一起使用而创建的,它基于操作到断言模式而不是大多数模拟框架中使用的记录到重播。 对于以前版本的 Python,有一个 unittest.mock 的反向移植。
基于 Python 中输入的模拟返回值
发布时间:2023/06/16 浏览次数:171 分类:Python
-
本文将介绍如何在 Python 中创建一个根据输入返回不同值的模拟函数。 我们还将向您展示如何测试我们的模拟函数。最后,我们将向您展示一些更高级的模拟函数的技术。
Python 模拟导入
发布时间:2023/06/16 浏览次数:129 分类:Python
-
在这篇 Python 文章中,我们将研究 mock 库并学习如何有效地使用它。 我们将从简单的示例开始,然后查看更高级的用法。Python 模拟导入 我们将学习模拟对象和模拟的用途和陷阱。
在 Python 中计算和显示凸包
发布时间:2023/06/16 浏览次数:142 分类:Python
-
因此,凸包是指围绕凸物体形状的边界。 本教程将教您在 Python 中计算和显示一组随机点的凸包。在 Python 中计算并显示一个凸包
Python 密码哈希
发布时间:2023/06/16 浏览次数:90 分类:Python
-
我们将了解密码散列以及如何使用名为 bcrypt 的第三方库加密 salt 和 hash 密码。 我们还研究了 Python 中 hashlib 库中的不同哈希算法。Python 中使用 bcrypt 库的 Salt 和 Hash 密码
Python 中的 Collatz 序列
发布时间:2023/06/16 浏览次数:180 分类:Python
-
Collatz数列是一种以1结尾的数字序列。据说当一个数字经过一组特定的运算后,最后剩下的数字一定是1。本文将解释如何编写程序,在 Python 中找到任何给定数字的 collatz 序列。Collatz 序列背后
Python 中的最长递增子序列
发布时间:2023/06/16 浏览次数:90 分类:Python
-
我们将学习什么是子序列以及如何使用 Python 中的 n 平方方法和二分搜索方法计算数组中最长的递增子序列。
使用 Python 将文件上传到 Google 云端硬盘
发布时间:2023/06/15 浏览次数:136 分类:Python
-
本文将介绍我们如何使用 Python 将文件上传到云盘,以 Google Drive 为例。 为此,我们将使用 Google Drive API。