Skip to content

Latest commit

 

History

History
207 lines (132 loc) · 8.32 KB

3985.md

File metadata and controls

207 lines (132 loc) · 8.32 KB

专业测试:Python Mock 库的逐步指南

译文:www.kdnuggets.com/testing-like-a-pro-a-step-by-step-guide-to-pythons-mock-library

Python 的 Mock 库

作者提供的图片 | DALLE-3 & Canva

测试软件对于确保在不同场景下的可靠性和功能性至关重要。然而,如果代码实现依赖于外部服务,这就会变成一个相当大的挑战。这时,模拟技术就派上用场了。Python 的 mock 库提供了创建模拟对象以替代真实对象的工具,使你的测试更容易维护。模拟技术有助于专注于组件的测试并加快测试周期。


我们的前三大课程推荐

1. Google 网络安全证书 - 快速进入网络安全职业道路。

2. Google 数据分析专业证书 - 提升你的数据分析技能

3. Google IT 支持专业证书 - 支持组织的 IT 需求


什么是模拟?

模拟是一种在软件测试中用来模拟真实对象的技术。真实对象被模拟对象替代,以模拟它们的功能,允许你在不同场景和隔离下测试代码。模拟特别适用于测试代码库的特定部分,而无需依赖与外部系统、数据库或其他复杂服务的交互。

让我通过一个例子来解释这个概念。假设你有一个使用外部 API 来检索数据的 web 应用程序。为了在不依赖真实 API 的情况下进行测试,你可以创建一个模拟对象,模仿 API 的回答。这样,你可以测试应用程序的功能,而不必依赖可能在开发过程中缓慢、不可靠或根本不可用的真实 API。

听起来很有趣,对吧?现在我们来详细探讨一下如何实际使用这个库。

使用 Mock 的逐步指南

第 1 步:导入 Mock 库

unittest.mock 是 Python 的标准库(3.3 及更新版本),提供了模拟对象以控制真实对象的行为。首先你需要导入 unittest.mock 库。

from unittest.mock import Mock, patch

第 2 步:创建模拟对象

创建模拟对象很简单。导入后,你可以像这样实例化一个模拟对象:

my_mock = Mock()

现在,my_mock 是一个模拟对象,你可以配置它以模拟真实对象的行为。

第 3 步:设置返回值

Mock 库提供了多种配置模拟对象和控制其行为的方法。例如,你可以指定一个方法在被调用时应该返回什么:

my_mock.some_method.return_value = 'Hello, World!'
print(my_mock.some_method()) 

输出:

Hello, World!

第 4 步:设置副作用

副作用是当模拟对象的方法被调用时触发的额外动作或行为,例如引发异常或执行函数。除了返回值之外,你还可以像这样定义属性或指定副作用。

def raise_exception():
    raise ValueError("An error occurred")

my_mock.some_method.side_effect = raise_exception

# This will raise a ValueError
try:
    my_mock.some_method()
except ValueError as e:
    print(e) 

输出:

An error occurred

在这个示例中,每当some_method()被调用时,ValueError会被引发。

第 5 步:断言调用

验证方法调用对于彻底测试至关重要。你可以使用断言来指定方法是否被调用、何时调用以及使用了什么参数。

my_mock.calculate_length('foo', 'bar')
my_mock.calculate_length.assert_called()
my_mock.calculate_length.assert_called_once()
my_mock.calculate_length.assert_called_with('foo', 'bar')
my_mock.calculate_length.assert_called_once_with('foo', 'bar')
  • assert_called(): 如果 calculate_length 至少被调用一次,则返回 True

  • assert_called_once(): 如果 calculate_length 仅被调用一次,则返回 True

  • assert_called_with('foo', 'bar'):如果 calculate_length 以相同的参数被调用,则返回 True

  • assert_called_once_with('foo', 'bar'):如果 calculate_length 以相同的参数被调用且仅被调用一次,则返回 True

如果这些断言在模拟对象上失败,将会引发AssertionError,表示期望的行为与模拟的实际行为不符。

第 6 步:使用修补

patch函数允许你在测试期间用模拟对象替换真实对象。如前所述,这对于模拟第三方库或 API 特别有用,确保你的测试与实际实现保持隔离。为了演示修补,请考虑以下从 URL 获取数据的示例函数。

# my_module.py
import requests

def fetch_data(url):
    response = requests.get(url)
    return response.json()

通过像这样修补‘requests.get’,你可以避免发出真正的HTTP请求:

# test_my_module.py
import unittest
from unittest.mock import patch
import my_module

class TestFetchData(unittest.TestCase):
    @patch('my_module.requests.get')

    def test_fetch_data(self, mock_get):
        # Set up the mock to return a specific response
        mock_get.return_value.json.return_value = {'key': 'value'}

        # Call the function to test
        result = my_module.fetch_data('http://example.com')

        # Check the result
        self.assertEqual(result, {'key': 'value'})

        # Verify that requests.get was called correctly
        mock_get.assert_called_once_with('http://example.com')

if __name__ == '__main__':
    unittest.main()

修补装饰器被添加在test_fetch_data function的上方,以用模拟对象替换requests.get函数。

第 7 步:模拟类

你可以模拟整个类及其方法,以模拟对象之间的交互。例如,你可以模拟一个数据库类来测试应用程序与数据库的交互,而不需要像这样设置真实的数据库连接:

# database.py
class Database:
    def connect(self):
        pass

    def save_user(self, user):
        pass

    def get_user(self, user_id):
        pass

# test_database.py
from unittest.mock import Mock

# Creating a mock database object
mock_db = Mock(spec=Database)

# Simulating method calls
mock_db.connect()
mock_db.save_user({"id": 1, "name": "Alice"})
mock_db.get_user(1)

# Verifying that the methods were called
mock_db.connect.assert_called_once()
mock_db.save_user.assert_called_once_with({"id": 1, "name": "Alice"})
mock_db.get_user.assert_called_once_with(1)

总结

这就是今天关于unittest.mock的文章,它是 Python 中一个强大的测试库。它使开发人员能够测试代码,确保对象之间的平稳交互。通过指定副作用、断言调用、模拟类和使用上下文管理器等高级功能,测试各种场景变得更加容易。今天就开始在你的测试中使用模拟对象,以确保更高质量的代码和更顺畅的部署。

Kanwal Mehreen**** Kanwal 是一名机器学习工程师和技术作家,对数据科学及人工智能与医学的交汇处充满热情。她共同撰写了电子书《用 ChatGPT 最大化生产力》。作为 2022 年亚太地区 Google 未来学者,她致力于推动多样性和学术卓越。她还被认可为 Teradata 多样性科技学者、Mitacs 全球研究学者和哈佛 WeCode 学者。Kanwal 是变革的坚定倡导者,创立了 FEMCodes 以赋能 STEM 领域的女性。

更多相关内容