欢迎访问宙启技术站
智能推送

Python中unittest.mock.patch的功能与用法

发布时间:2023-12-17 21:31:29

unittest.mock.patch是Python标准库中unittest.mock模块提供的一个装饰器,用于在单元测试中模拟或替代某个对象或方法。它可以用来替换被测试代码中的任何对象,包括模块、类、实例的方法等,从而在测试中控制被替换对象的行为和返回值。

patch功能的用法如下:

1. 作为装饰器使用:

patch可以作为一个装饰器应用到单元测试的函数上,用于临时替换被测试函数中的某个对象。被替换的对象将被一个新的Mock对象替代。

下面是一个使用patch作为装饰器的例子:

from unittest import TestCase, mock

class MyTest(TestCase):
    @mock.patch('module_name.class_name.method_name')
    def test_my_method(self, mock_method):
        # 测试代码
        pass

2. 用于上下文管理:

patch也可以作为一个上下文管理器使用,用于临时替换被测试函数中的某个对象。被替换的对象将被一个新的Mock对象替代。

下面是一个使用patch作为上下文管理器的例子:

from unittest import TestCase, mock

class MyTest(TestCase):
    def test_my_method(self):
        with mock.patch('module_name.class_name.method_name') as mock_method:
            # 测试代码
            pass

3. 用于函数调用:

patch还可以直接用于函数调用,用于临时替换被测试函数中的某个对象。被替换的对象将被一个新的Mock对象替代,但是这个替换只在函数调用期间有效,函数调用之后对象将恢复原来的状态。

下面是一个使用patch进行函数调用的例子:

from unittest import TestCase, mock

class MyTest(TestCase):
    def test_my_method(self):
        with mock.patch('module_name.class_name.method_name') as mock_method:
            # 函数调用代码...
            mock_method.assert_called_once()

除了以上常用的用法之外,patch还支持其他一些选项和参数,如autospec、new等,用于控制被替换对象的行为。

下面举一个具体的例子来阐述patch的用法:

假设有一个用户管理系统,其中有一个User类,具有新增用户和获取用户信息的方法。现在需要对这些方法进行单元测试。

# user.py
class User:
    def __init__(self, name):
        self.name = name

    def get_info(self):
        return f"User name: {self.name}"

def add_user(name):
    user = User(name)
    return user

def get_user_info(user):
    return user.get_info()

现在我们要对add_user函数和get_user_info函数进行单元测试,但是在单元测试中我们不希望实际去创建User对象和调用User对象的方法,而是希望使用Mock对象来替代User对象。

# test_user.py
from unittest import TestCase, mock
from user import add_user, get_user_info

class UserTest(TestCase):
    @mock.patch('user.User')  # 使用patch装饰器
    def test_add_user(self, mock_user):
        # 设置Mock对象的行为
        mock_user_instance = mock_user.return_value
        mock_user_instance.name = 'Mock User'

        # 调用add_user函数
        result = add_user('John Doe')

        # 验证add_user函数的返回值和Mock对象的行为
        self.assertEqual(result.name, 'Mock User')
        mock_user.assert_called_once_with('John Doe')
        mock_user_instance.get_info.assert_not_called()

    def test_get_user_info(self):
        with mock.patch('user.User') as mock_user:  # 使用patch上下文管理器
            # 设置Mock对象的行为
            mock_user_instance = mock_user.return_value
            mock_user_instance.get_info.return_value = 'Mock User Info'

            # 创建一个Mock对象
            mock_user_obj = mock.Mock()

            # 调用get_user_info函数
            result = get_user_info(mock_user_obj)

            # 验证get_user_info函数的返回值和Mock对象的行为
            self.assertEqual(result, 'Mock User Info')
            mock_user_instance.get_info.assert_called_once()
            mock_user.assert_called_once_with(mock_user_obj)
       

以上代码中,我们使用patch装饰器和patch上下文管理器分别对不同的函数进行mock。在 个测试中,我们使用patch装饰器对User类进行mock,并设定mock对象的行为,然后调用add_user函数并验证返回值和mock对象的行为。

在第二个测试中,我们使用patch上下文管理器对User类进行mock,并设定mock对象的行为,然后创建一个mock对象作为参数调用get_user_info函数,并验证返回值和mock对象的行为。

通过使用patch,我们可以对被测试代码中的对象进行替换,从而在测试中控制对象的行为和返回值,使得测试变得简单、可控和可靠。