unittest.mock

1、Python mock库简介

2、mock库的使用

图片

mock库简介

PART 01

1.1

mock库简介

Python的mock库是一个用于创建和测试模拟对象的库。模拟对象可以模拟真实对象的行为,例如函数、类或方法。这对于单元测试和测试驱动开发(TDD)非常有用,因为它允许你隔离代码并测试其特定部分。

1.2

mock特点

Python的mock库在测试中起着至关重要的作用,其具有以下特点:

  • 隔离性:Mock提供了一种隔离被测试代码与其依赖之间的方式,从而使得测试更加稳定和可靠。通过隔离依赖,Mock可以在不同环境中测试同一份被测代码,或者在同一环境中测试不同的被测代码。

  • 灵活性:Mock提供了一种非常灵活的方式来创建虚拟对象,从而模拟所需要的行为。Mock利用Python中的动态特性,可以很容易地模拟任何对象和方法,并定制它们的行为来满足测试需求。

  • 可扩展性:Mock提供了一种轻量级的测试工具,但又非常易于扩展。可以使用Mock来实现更高级的测试功能,并且可以根据需要自定义Mock对象的行为,从而让测试更加丰富和精准。

  • 可读性:Mock设计简单易懂,使用起来非常直观。Mock对象可以很容易地集成到测试框架中,并且可以根据需要自定义Mock对象的输出,从而让测试结果更具可读性。

  • 可设置和可检查:使用Mock可以在测试中设置模拟对象的行为和检查模拟对象的行为。

  • 易于维护:使用Mock可以使得测试代码更加简洁和易于维护。

1.3

mock使用场景

Python中的mock主要用于模拟测试环境中的对象,确保测试可以顺利进行,即使真实对象不可用或不易获取。以下是一些常见的使用场景:

  • 模拟方法调用:当需要确认一个方法是否被系统中的其他部分调用过,并且调用时使用了正确的参数时,可以使用mock来模拟该方法的调用。

  • 前后端并行开发:在前后端分离的开发模式中,后端服务可能尚未完成,此时可以使用mock来模拟后端服务,使得前端可以独立进行开发和测试。

  • 模拟无法访问的资源:对于依赖第三方服务或接口的情况,如果这些服务或接口暂时无法访问,可以使用mock来模拟这些服务或接口的行为,保证开发和测试工作的连续性。

  • 隔离系统:在进行单元测试时,为了避免脏数据干扰测试结果,可以使用mock来隔离系统,确保测试环境的稳定性。

  • 提高测试效率:通过模拟耗时的操作,如网络请求、数据库操作等,可以提高测试的效率,使得测试过程更加快速和可靠。

  • 保护敏感数据:在测试过程中,可能需要模拟涉及敏感数据的实际操作,如支付系统的扣款操作,此时使用mock可以避免实际操作对敏感数据的影响。

图片

mock库使用

PART 02

2.1

mock库安装

在Python2.x中mock是一个单独模块,需要单独安装。

pip install mock

在Python3.x中,mock已经被集成到了unittest单元测试框架中,所以可以直接使用。

from unittest.mock import Mock

2.2

创建mock对象

在Python的unittest.mock库中,创建Mock对象时可以传递一些参数来定制Mock的行为。以下是一些常用的参数:

  • spec: 用于指定要模拟的对象的规范。它可以是任何对象,类,方法或属性。Mock对象将模拟该规范对象的所有方法,属性等。

  • spec_set: 与spec类似,但它是一个可选项。如果同时设置了spec和spec_set,那么spec_set将覆盖spec。

  • call_args: 一个元组或列表,用于指定模拟对象被调用时传递的参数。

  • call_args_list: 一个列表,包含多个元组或列表,用于指定模拟对象被多次调用时传递的参数。

  • return_value: 用于指定模拟对象被调用时返回的值。

  • side_effect: 用于指定模拟对象被调用时的副作用。它可以是任何可调用的对象或异常。

  • name: 用于指定模拟对象的名称。

  • create: 一个布尔值,用于指定是否创建模拟对象。默认为True。

  • wraps: 一个可调用对象,用于包装模拟对象。这可以用于模拟装饰器或函数修饰器。

  • **kwargs: 其他关键字参数将作为属性添加到模拟对象中。

rom unittest.mock import Mock
  
mock_obj = Mock(
    spec=MyClass, # 模拟MyClass类
    call_args=(3, 2), # 模拟调用时的参数为(3, 2)
    return_value=5, # 模拟调用时返回5
    side_effect=ValueError("Mock error"), # 模拟调用时引发ValueError异常
    name="mocked_object", # 模拟对象的名称为"mocked_object"
    wraps=original_function, # 将模拟对象包装为original_function的调用
    **kwargs # 将其他关键字参数作为属性添加到模拟对象中
)

2.3

mock常用属性和方法

  1. return_value: 设置模拟对象的返回值。这允许你指定当调用模拟对象时应该返回什么值。

from unittest.mock import MagicMock

# 创建一个模拟对象
mock_obj = MagicMock()

# 设置模拟对象的返回值为42
mock_obj.return_value = 42

# 调用模拟对象的方法,并获取返回值
result = mock_obj()
print(result) # 输出42
  1. side_effect: 设置模拟对象调用时的负面效果。这可以用来模拟方法调用时可能抛出的异常,或者根据调用顺序返回不同的值。

from unittest.mock import MagicMock

# 创建一个模拟对象
mock_obj = MagicMock()

# 设置模拟对象在被调用时抛出异常
mock_obj.side_effect = Exception("Error")

# 调用模拟对象的方法,并捕获异常
try:
    result = mock_obj()
except Exception as e:
    print(e) # 输出"Error"
  1. call_count: 获取模拟对象被调用的次数。这在测试中非常有用,因为它可以帮助你验证一个方法是否被调用了预期的次数。

from unittest.mock import MagicMock

# 创建一个模拟对象
mock_obj = MagicMock()

# 调用模拟对象的方法两次
mock_obj()
mock_obj()

# 获取模拟对象被调用的次数
count = mock_obj.call_count
print(count) # 输出2
  1. assert_called_once_with(...): 检查模拟对象是否恰好被调用了一次,并且传递了指定的参数。

from unittest.mock import MagicMock

# 创建一个模拟对象
mock_obj = MagicMock()

# 调用模拟对象的方法,并传递参数"hello"和"world"
mock_obj("hello", "world")

# 检查模拟对象是否恰好被调用了一次,并且传递了参数"hello"和"world"
mock_obj.assert_called_once_with("hello", "world")
  1. assert_called_any_with(...): 检查模拟对象是否至少被调用了一次,并且可以与任何给定的参数一起调用。

from unittest.mock import MagicMock

# 创建一个模拟对象
mock_obj = MagicMock()

# 调用模拟对象的方法,并传递不同的参数
mock_obj("hello", "world")
mock_obj("foo", "bar")

# 检查模拟对象是否至少被调用了一次,并且可以与任何给定的参数一起调用
mock_obj.assert_called_any_with("hello", "world")
mock_obj.assert_called_any_with("foo", "bar")
  1. reset_mock(): 重置模拟对象的状态,清除所有之前的调用记录。

from unittest.mock import MagicMock

# 创建一个模拟对象
mock_obj = MagicMock()

# 调用模拟对象的方法两次
mock_obj()
mock_obj()

# 重置模拟对象的状态,清除所有之前的调用记录
mock_obj.reset_mock()

# 再次调用模拟对象的方法,并获取调用次数
count = mock_obj.call_count
print(count) # 输出0

2.3

mock的使用案例

案例一:模拟函数调用。使用Mock库来模拟函数my_function的调用。通过设置模拟函数的return_value属性为5,我们告诉模拟函数在调用时返回该值。然后,我们调用模拟函数并传入参数(3, 2),它将返回5。

from unittest.mock import Mock
  
def my_function(arg1, arg2):  
    return arg1 + arg2
  
mock_function = Mock(spec=my_function)
mock_function.return_value = 5  
print(mock_function(3, 2)) # 输出: 5

案例二:模拟类的方法调用。使用Mock库来模拟类MyClass的方法my_method的调用。通过设置模拟对象的my_method方法的返回值为5,我们告诉模拟方法在调用时返回该值。然后,我们调用模拟对象的my_method方法并传入参数(3, 2),它将返回5。注意,由于模拟对象继承了类的方法,我们可以像调用普通方法一样调用模拟对象的方法。

from unittest.mock import Mock
  
class MyClass:  
    def my_method(self, arg1, arg2):  
        return arg1 + arg2
  
mock_obj = Mock(spec=MyClass)
mock_obj.my_method.return_value = 5  
print(mock_obj.my_method(3, 2)) # 输出: 5

案例三:模拟对象属性访问。使用Mock库来模拟对象属性访问。通过设置模拟对象的属性my_attr为"mocked value",我们告诉模拟对象在访问该属性时返回该值。然后,我们访问模拟对象的my_attr属性,它将返回"mocked value"。由于模拟对象继承了类的属性,因此我们可以像访问普通属性一样访问模拟对象的属性。

from unittest.mock import Mock
  
class MyClass:  
    def __init__(self):  
        self.my_attr = None  
  
mock_obj = Mock(spec=MyClass)
mock_obj.my_attr = "mocked value"  
print(mock_obj.my_attr) # 输出: mocked value

案例四:模拟请求接口数据返回。在下面的案例中,我们使用了unittest模块自带的mock来模拟接口的返回数据。通过使用mock.patch装饰器,我们可以替换被测试函数中的requests.get方法,并设置mock_get的返回值。然后,我们调用被测试函数,并断言返回值是否符合预期。最后,我们还可以使用assert_called_once_with方法来断言mock_get方法是否被调用。

import unittest
from unittest import mock

# 要测试的函数
def get_data_from_api(url):
    # 假设这里是调用了一个真实的接口,并返回了数据
    response = requests.get(url)
    return response.json()

class TestAPI(unittest.TestCase):
    def test_get_data_from_api(self):
        # 使用mock.patch装饰器来替换被测试函数中的requests.get方法
        with mock.patch('requests.get') as mock_get:
            # 设置mock_get的返回值
            mock_get.return_value.json.return_value = {'status': 'success', 'data': 'mocked data'}
            
            # 调用被测试函数
            result = get_data_from_api('http://example.com/api')
            
            # 断言返回值是否符合预期
            self.assertEqual(result, {'status': 'success', 'data': 'mocked data'})
            
            # 断言mock_get方法是否被调用
            mock_get.assert_called_once_with('http://example.com/api')

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

Python mock库 (qq.com)

图片

END

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值