掌握 Python Mock和Patch:模拟测试1

本文详细介绍了Python中的模拟测试技术,包括使用unittest.mock库中的Mock和MagicMock类创建模拟对象,以及patch装饰器和上下文管理器替换真实对象。通过实例展示了如何在单元测试中移除外部依赖,确保测试的稳定性和可靠性。
摘要由CSDN通过智能技术生成

您听说过 Python mock 和 patch 是改进单元测试的一种方法吗?您将在本教程中学习如何使用它们。

单元测试是软件开发的关键,因为它们能确保代码按计划运行。

Python 有许多强大的工具,可以通过创建 mock 在受控环境中运行单元测试。Mock 类是 unittest.mock 库的一部分,它允许创建 mock 对象。同一库中的 patch 函数允许用模拟对象替换真实对象。

让我们来了解一下 Python 模拟!

在 Python 中使用哪个模块进行模拟?

模拟是单元测试中使用的一种技术,它可以用模拟对象替换代码中不容易测试的部分,模拟对象复制了真实对象的行为。

Python unittest.mock 库为在单元测试中构建和操作模拟对象提供了一个框架。

模拟对象有助于创建受控的测试环境。它们模拟真实对象的行为,但其输入和输出是可以控制的。这样,您就可以隔离和测试那些由于外部依赖性而很难测试的代码。

通过导入 unittest 模块,您可以使用 mock 类和 patch 函数

import unittest

如何使用 Python Mock 类创建模拟对象?

要创建 mock 对象,可以使用 unittest 模块中的 Mock 类。

>>> from unittest.mock import Mock
>>> Mock
<class 'unittest.mock.Mock'>

我们从 unittest.mock 中导入了 Mock 类。现在我们可以创建一个 Mock 对象。

>>> mock = Mock()
>>> mock
<Mock id='140397919063152'>

Mock 的目的是替换真实的 Python 对象,但要做到这一点,Mock 必须提供与真实对象相同的方法和属性。

那么,Python 模拟是如何处理这个问题的呢?

让我们试着获取我们创建的 mock 的属性值或调用 mock 的方法:

>>> mock.length
<Mock name='mock.length' id='140397919064016'>
>>> mock.calculate_length(3, 6)
<Mock name='mock.calculate_length()' id='140398188475584'>

你可以看到,这两种方法都起作用了。这是因为 Mock 类动态创建了属性和方法。这使得模拟对象可以替代任何真实对象。

下面是我们的模拟对象的所有属性:

>>> mock.__dict__
{
   '_mock_return_value': sentinel.DEFAULT, '_mock_parent': None, '_mock_name': None, '_mock_new_name': '', '_mock_new_parent': None, '_mock_sealed': False, '_spec_class': None, '_spec_set': None, '_spec_signature': None, '_mock_methods': None, '_spec_asyncs': [], '_mock_children': {
   'length': <Mock name='mock.length' id='140397919064016'>, 'calculate_length': <Mock name='mock.calculate_length' id='140397919105184'>}, '_mock_wraps': None, '_mock_delegate': None, '_mock_called': False, '_mock_call_args': None, '_mock_call_count': 0, '_mock_call_args_list': [], '_mock_mock_calls': [call.calculate_length(3, 6)], 'method_calls': [call.calculate_length(3, 6)], '_mock_unsafe': False, '_mock_side_effect': None}

其中最有趣的是"_mock_children "属性,它包含在上述代码中动态创建的属性和方法。

在访问属性或调用方法时,Mock 对象会自动创建子对象。

断言对 Python 模拟的调用

在上一节中,我们调用了 mock 对象的一个方法。现在我们可以断言模拟对象上的特定方法已被调用。

下面是成功的断言。这些断言测试了 mock 的 calculate_length() 方法是否被调用:

  1. 已被调用。
  2. 已调用一次。
  3. 已调用参数 3 和 6。
  4. 已调用一次,参数为 3 和 6。

如果 mock 方法的断言失败,mock 会引发 AssertionError。

再次调用 mock 上的 calculate_length() 方法,看看 assert_called_once() 断言是如何失败的。

>>> mock.calculate_length(3, 6)
<Mock name='mock.calculate_length()' id='140398188475584'>
>>> mock.calculate_length.assert_called_once()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/opt/anaconda3/lib/python3.8/unittest/mock.py", line 892, in assert_called_once
    raise AssertionError(msg)
AssertionError: Expected 'calculate_length' to have been called once. Called 2 times.
Calls: [call(3, 6), call(3, 6)].

Python 解释器希望该方法被调用一次,但它却被调用了 2 次。

如果断言与调用 mock 时使用的参数不匹配(例如,在这种情况下是 4 和 6,而不是 3 和 6),还会出现 AssertionError。

>>> mock.calculate_length.assert_called_with(4, 6)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/opt/anaconda3/lib/python3.8/unittest/mock.py", line 913, in assert_called_with
    raise AssertionError(_error_message()) from cause
AssertionError: expected call not found.
Expected: calculate_length
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值