• python_Mock基本使用


    ## 1.mock简介

    1. py3已将mock集成到unittest库中
    2. 为的就是更好的进行单元测试
    3. 简单理解,模拟接口返回参数
    4. 通俗易懂,直接修改接口返回参数的值
    5. 官方文档:https://docs.python.org/zh-cn/3/library/unittest.mock.html

    ## 2.mock作用

    **解决依赖问题,达到解耦作用**
    当我们测试某个**目标接口(模块)时**,该**接口依赖其他接口**,当被依赖的接口未开发完成时,可以用**mock模拟被依赖接口**,完成目标接口的测试

    ## 模拟复杂业务的接口
    当我们测试某个**目标接口(模块)**,该接口**依赖一个非常复杂的接口**时****,可以**用mock来模拟这个复杂的业务接口**;也解决接口依赖一样的原理

    ## 单元测试
    如果某个接口(模块)未开发完成时,又需要编写测试用例,则可以通过mock模拟该接口(模块)进行测试

    ## 前后端联调

    前端开发的页面需要根据后端返回的不同状态码展示不同的页面,当后端接口未开发完成时,也可通过mock来模拟后端接口返回自己想要的数据

    ## 3.mock类解读

    class Mock(spec=None,side_effect=None,return_value=DEFFAULT,name=None)

    - secp:定义mock对象的属性值,可以是列表,字符串,甚至一个对象或者实例
    - side_effect:可以用来抛出异常或者动态改变返回值,它必须是一个
    - iterator(列表),它会覆盖return_value
    - return_value:定义mock方法的返回值,它可以是一个值,可以是一个对象(如果存在side_effect参数那这个就没有用,也就是不能同时用)
    - name:作为mock对象的一个标识,在print时可以看到

    ## 4.mock实际使用

    def add(self, a, b):
    """两个数相加"""
    pass
    
    
    class TestSub(unittest.TestCase):
    """测试两个数相加用例"""
    
    def test_sub(self):
    # 创建一个mock对象 return_value代表mock一个数据
    mock_add = mock.Mock(return_value=15)
    # 将mock对象赋予给被测函数
    add = mock_add
    # 调用被测函数
    result = add(5, 5)
    # 断言实际结果和预期结果
    self.assertEqual(result, 15)

    ## 一个完成开发的功能如何测试?

    class SubClass(object):
    def add(self, a, b):
    """两个数相加"""
    return a + b
    
    
    class TestSub(unittest.TestCase):
    """测试两个数相加用例"""
    
    
    def test_add2(self):
    # 初始化被测函数类实例
    sub = SubClass()
    # 创建一个mock对象 return_value代表mock一个数据
    # 传递side_effect关键字参数, 会覆盖return_value参数值, 使用真实的add方法测试
    sub.add = Mock(return_value=15, side_effect=sub.add)
    # 调用被测函数
    result = sub.add(5, 5)
    # 断言实际结果和预期结果
    self.assertEqual(result, 10)

    - **side_effect:**这里给的参数值是sub.add相当于add方法的地址,当我们调用add方法时就会调用真实的add方法
    - **简单理解成:**传递了**side_effect**参数且值为被测函数地址时,mock不会起作用;**两者不可共存**
    - 另外,side_effect接受的是一个可迭代序列,当传递多个值时,每次调用mock时会返回不同的值;如下

    mock_obj = mock.Mock(side_effect= [1,2,3])
    print(mock_obj())
    print(mock_obj())
    print(mock_obj())
    print(mock_obj())
    
    # 输出
    Traceback (most recent call last):
    1
    File "D:/MyThreading/mymock.py", line 37, in <module>
    2
    print(mock_obj())
    3
    File "C:Python36libunittestmock.py", line 939, in __call__
    return _mock_self._mock_call(*args, **kwargs)
    File "C:Python36libunittestmock.py", line 998, in _mock_call
    result = next(effect)
    StopIteration

    ## 存在依赖关系的功能如何测试?

    # 支付类
    class Payment:
    
    def requestOutofSystem(self, card_num, amount):
    '''
    请求第三方外部支付接口,并返回响应码
    :param card_num: 卡号
    :param amount: 支付金额
    :return: 返回状态码,200 代表支付成功,500 代表支付异常失败
    '''
    # 第三方支付接口请求地址(故意写错)
    url = "http://third.payment.pay/"
    # 请求参数
    data = {"card_num": card_num, "amount": amount}
    response = requests.post(url, data=data)
    # 返回状态码
    return response.status_code
    
    def doPay(self, user_id, card_num, amount):
    '''
    支付
    :param userId: 用户ID
    :param card_num: 卡号
    :param amount: 支付金额
    :return:
    '''
    try:
    # 调用第三方支付接口请求进行真实扣款
    resp = self.requestOutofSystem(card_num, amount)
    print('调用第三方支付接口返回结果:', resp)
    except TimeoutError:
    # 如果超时就重新调用一次
    print('重试一次')
    resp = self.requestOutofSystem(card_num, amount)
    
    if resp == 200:
    # 返回第三方支付成功,则进行系统里面的扣款并记录支付记录等操作
    print("{0}支付{1}成功!!!进行扣款并记录支付记录".format(user_id, amount))
    return 'success'
    
    elif resp == 500:
    # 返回第三方支付失败,则不进行扣款
    print("{0}支付{1}失败!!不进行扣款!!!".format(user_id, amount))
    return 'fail'
    
    # 单元测试类
    class payTest(unittest.TestCase):
    
    def test_pay_success(self):
    pay = Payment()
    # 模拟第三方支付接口返回200
    pay.requestOutofSystem = mock.Mock(return_value=200)
    resp = pay.doPay(user_id=1, card_num='12345678', amount=100)
    self.assertEqual('success', resp)
    
    def test_pay_fail(self):
    pay = Payment()
    # 模拟第三方支付接口返回500
    pay.requestOutofSystem = mock.Mock(return_value=500)
    resp = pay.doPay(user_id=1, card_num='12345678', amount=100)
    self.assertEqual('fail', resp)
    
    def test_pay_time_success(self):
    pay = Payment()
    # 模拟第三方支付接口首次支付超时,重试第二次成功
    pay.requestOutofSystem = mock.Mock(side_effect=[TimeoutError, 200])
    resp = pay.doPay(user_id=1, card_num='12345678', amount=100)
    self.assertEqual('success', resp)
    
    def test_pay_time_fail(self):
    pay = Payment()
    # 模拟第三方支付接口首次支付超时,重试第二次失败
    pay.requestOutofSystem = mock.Mock(side_effect=[TimeoutError, 500])
    resp = pay.doPay(user_id=1, card_num='12345678', amount=100)
    self.assertEqual('fail', resp)

    也许有小伙伴会问,第三方支付都不能用,我们的测试结果是否是有效的呢?

    通常在测试一个模块的时候,是可以认为**其他模块的功能是正常的,只针对目标模块进行测试是没有任何问题的**,所以说测试结果也是正确的

    @patch('module名字.方法名') 
    @patch.object(类名, '方法名'
    # 装饰类演示
    from mock import Mock, patch
    
    
    # 单独的相乘函数
    def multiple(a, b):
    return a * b
    
    
    # 单独的捕获Exception函数
    def is_error():
    try:
    os.mkdir("11")
    return False
    except Exception as e:
    return True
    
    
    # 计算类,包含add方法
    class calculator(object):
    def add(self, a, b):
    return a + b
    
    
    # 装饰类演示 - 单元测试类
    class TestProducer(unittest.TestCase):
    
    # case执行前
    def setUp(self):
    self.calculator = calculator()
    
    # mock一个函数,注意也要指定module
    @patch('mock_learn.multiple')
    def test_multiple(self, mock_multiple):
    mock_multiple.return_value = 3
    self.assertEqual(multiple(8, 14), 3)
    
    # mock一个类对象的方法
    @patch.object(calculator, 'add')
    def test_add(self, mock_add):
    mock_add.return_value = 3
    self.assertEqual(self.calculator.add(8, 14), 3)
    
    # mock调用方法返回多个不同的值
    @patch.object(calculator, 'add')
    def test_effect(self, mock_add):
    mock_add.side_effect = [1, 2, 3]
    self.assertEqual(self.calculator.add(8, 14), 1)
    self.assertEqual(self.calculator.add(8, 14), 2)
    self.assertEqual(self.calculator.add(8, 14), 3)
    
    # mock的函数抛出Exception
    @patch('os.mkdir')
    def test_exception(self, mkdir):
    mkdir.side_effect = Exception
    self.assertEqual(is_error(), True)
    
    # mock多个函数,注意函数调用顺序
    @patch.object(calculator, 'add')
    @patch('mock_learn.multiple')
    def test_more(self, mock_multiple, mock_add):
    mock_add.return_value = 1
    mock_multiple.return_value = 4
    self.assertEqual(self.calculator.add(3, 3), 1)
    self.assertEqual(multiple(3, 3), 4)
  • 相关阅读:
    SQL Server 2008 R2下载地址
    [转]sqlserver2014两台不同服务器上数据库同步
    笔记本(ThinkPad)怎样关闭触摸板
    10 Free Image Hosting Sites for Your Photos
    Photobucket不能用了怎么办?推荐10个在线图片储存服务!
    证书错误 导航已阻止 无法跳转 最终解决
    用websploit获取管理员后台地址
    10 Free Image Hosting Sites for Your Photos
    Css3动画属性总汇
    23个适合logo设计的常用英文字体
  • 原文地址:https://www.cnblogs.com/Jackbk/p/12691973.html
Copyright © 2020-2023  润新知