python接口自动化测试 之mock模块基本使用介绍

mock作用
解决依赖问题,达到解耦作用

当我们测试某个目标接口(模块) 时,该接口依赖其他接口 ,当被依赖的接口未开发完成时,可以用mock模拟被依赖接口,完成目标接口的测试

模拟复杂业务的接口

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

单元测试

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

前后端联调

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

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时可以看到

mock实际使用
一个未开发完成的功能如何测试?
复制代码
  1. 1 def add(self, a, b):

  2. 2 """两个数相加"""

  3. 3 pass

  4. 4

  5. 5

  6. 6 class TestSub(unittest.TestCase):

  7. 7 """测试两个数相加用例"""

  8. 8

  9. 9 def test_sub(self):

  10. 10 # 创建一个mock对象 return_value代表mock一个数据

  11. 11 mock_add = mock.Mock(return_value=15)

  12. 12 # 将mock对象赋予给被测函数

  13. 13 add = mock_add

  14. 14 # 调用被测函数

  15. 15 result = add(5, 5)

  16. 16 # 断言实际结果和预期结果

  17. 17 self.assertEqual(result, 15)

一个完成开发的功能如何测试?
  1. class SubClass(object):

  2. def add(self, a, b):

  3. """两个数相加"""

  4. return a + b

  5. class TestSub(unittest.TestCase):

  6. """测试两个数相加用例"""

  7. def test_add2(self):

  8. # 初始化被测函数类实例

  9. sub = SubClass()

  10. # 创建一个mock对象 return_value代表mock一个数据

  11. # 传递side_effect关键字参数, 会覆盖return_value参数值, 使用真实的add方法测试

  12. sub.add = Mock(return_value=15, side_effect=sub.add)

  13. # 调用被测函数

  14. result = sub.add(5, 5)

  15. # 断言实际结果和预期结果

  16. self.assertEqual(result, 10)

side_effect:这里给的参数值是sub.add相当于add方法的地址,当我们调用add方法时就会调用真实的add方法

简单理解成:传递了side_effect参数且值为被测函数地址时,mock不会起作用;两者不可共存

另外,side_effect接受的是一个可迭代序列,当传递多个值时,每次调用mock时会返回不同的值;如下

复制代码
  1. 1 mock_obj = mock.Mock(side_effect= [1,2,3])

  2. 2 print(mock_obj())

  3. 3 print(mock_obj())

  4. 4 print(mock_obj())

  5. 5 print(mock_obj())

  6. 6

  7. 7 # 输出

  8. 8 Traceback (most recent call last):

  9. 9 1

  10. 10 File "D:/MyThreading/mymock.py", line 37, in <module>

  11. 11 2

  12. 12 print(mock_obj())

  13. 13 3

  14. 14 File "C:\Python36\lib\unittest\mock.py", line 939, in __call__

  15. 15 return _mock_self._mock_call(*args, **kwargs)

  16. 16 File "C:\Python36\lib\unittest\mock.py", line 998, in _mock_call

  17. 17 result = next(effect)

  18. 18 StopIteration

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

复制代码
  1. 1 # 支付类

  2. 2 class Payment:

  3. 3

  4. 4 def requestOutofSystem(self, card_num, amount):

  5. 5 '''

  6. 6 请求第三方外部支付接口,并返回响应码

  7. 7 :param card_num: 卡号

  8. 8 :param amount: 支付金额

  9. 9 :return: 返回状态码,200 代表支付成功,500 代表支付异常失败

  10. 10 '''

  11. 11 # 第三方支付接口请求地址(故意写错)

  12. 12 url = "http://third.payment.pay/"

  13. 13 # 请求参数

  14. 14 data = {"card_num": card_num, "amount": amount}

  15. 15 response = requests.post(url, data=data)

  16. 16 # 返回状态码

  17. 17 return response.status_code

  18. 18

  19. 19 def doPay(self, user_id, card_num, amount):

  20. 20 '''

  21. 21 支付

  22. 22 :param userId: 用户ID

  23. 23 :param card_num: 卡号

  24. 24 :param amount: 支付金额

  25. 25 :return:

  26. 26 '''

  27. 27 try:

  28. 28 # 调用第三方支付接口请求进行真实扣款

  29. 29 resp = self.requestOutofSystem(card_num, amount)

  30. 30 print('调用第三方支付接口返回结果:', resp)

  31. 31 except TimeoutError:

  32. 32 # 如果超时就重新调用一次

  33. 33 print('重试一次')

  34. 34 resp = self.requestOutofSystem(card_num, amount)

  35. 35

  36. 36 if resp == 200:

  37. 37 # 返回第三方支付成功,则进行系统里面的扣款并记录支付记录等操作

  38. 38 print("{0}支付{1}成功!!!进行扣款并记录支付记录".format(user_id, amount))

  39. 39 return 'success'

  40. 40

  41. 41 elif resp == 500:

  42. 42 # 返回第三方支付失败,则不进行扣款

  43. 43 print("{0}支付{1}失败!!不进行扣款!!!".format(user_id, amount))

  44. 44 return 'fail'

  45. 45

  46. 46 # 单元测试类

  47. 47 class payTest(unittest.TestCase):

  48. 48

  49. 49 def test_pay_success(self):

  50. 50 pay = Payment()

  51. 51 # 模拟第三方支付接口返回200

  52. 52 pay.requestOutofSystem = mock.Mock(return_value=200)

  53. 53 resp = pay.doPay(user_id=1, card_num='12345678', amount=100)

  54. 54 self.assertEqual('success', resp)

  55. 55

  56. 56 def test_pay_fail(self):

  57. 57 pay = Payment()

  58. 58 # 模拟第三方支付接口返回500

  59. 59 pay.requestOutofSystem = mock.Mock(return_value=500)

  60. 60 resp = pay.doPay(user_id=1, card_num='12345678', amount=100)

  61. 61 self.assertEqual('fail', resp)

  62. 62

  63. 63 def test_pay_time_success(self):

  64. 64 pay = Payment()

  65. 65 # 模拟第三方支付接口首次支付超时,重试第二次成功

  66. 66 pay.requestOutofSystem = mock.Mock(side_effect=[TimeoutError, 200])

  67. 67 resp = pay.doPay(user_id=1, card_num='12345678', amount=100)

  68. 68 self.assertEqual('success', resp)

  69. 69

  70. 70 def test_pay_time_fail(self):

  71. 71 pay = Payment()

  72. 72 # 模拟第三方支付接口首次支付超时,重试第二次失败

  73. 73 pay.requestOutofSystem = mock.Mock(side_effect=[TimeoutError, 500])

  74. 74 resp = pay.doPay(user_id=1, card_num='12345678', amount=100)

  75. 75 self.assertEqual('fail', resp)

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

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

mock装饰器

一共两种格式

  1. @patch('module名字.方法名')
  2. @patch.object(类名, '方法名')
复制代码
  1. 1 # 装饰类演示

  2. 2 from mock import Mock, patch

  3. 3

  4. 4

  5. 5 # 单独的相乘函数

  6. 6 def multiple(a, b):

  7. 7 return a * b

  8. 8

  9. 9

  10. 10 # 单独的捕获Exception函数

  11. 11 def is_error():

  12. 12 try:

  13. 13 os.mkdir("11")

  14. 14 return False

  15. 15 except Exception as e:

  16. 16 return True

  17. 17

  18. 18

  19. 19 # 计算类,包含add方法

  20. 20 class calculator(object):

  21. 21 def add(self, a, b):

  22. 22 return a + b

  23. 23

  24. 24

  25. 25 # 装饰类演示 - 单元测试类

  26. 26 class TestProducer(unittest.TestCase):

  27. 27

  28. 28 # case执行前

  29. 29 def setUp(self):

  30. 30 self.calculator = calculator()

  31. 31

  32. 32 # mock一个函数,注意也要指定module

  33. 33 @patch('mock_learn.multiple')

  34. 34 def test_multiple(self, mock_multiple):

  35. 35 mock_multiple.return_value = 3

  36. 36 self.assertEqual(multiple(8, 14), 3)

  37. 37

  38. 38 # mock一个类对象的方法

  39. 39 @patch.object(calculator, 'add')

  40. 40 def test_add(self, mock_add):

  41. 41 mock_add.return_value = 3

  42. 42 self.assertEqual(self.calculator.add(8, 14), 3)

  43. 43

  44. 44 # mock调用方法返回多个不同的值

  45. 45 @patch.object(calculator, 'add')

  46. 46 def test_effect(self, mock_add):

  47. 47 mock_add.side_effect = [1, 2, 3]

  48. 48 self.assertEqual(self.calculator.add(8, 14), 1)

  49. 49 self.assertEqual(self.calculator.add(8, 14), 2)

  50. 50 self.assertEqual(self.calculator.add(8, 14), 3)

  51. 51

  52. 52 # mock的函数抛出Exception

  53. 53 @patch('os.mkdir')

  54. 54 def test_exception(self, mkdir):

  55. 55 mkdir.side_effect = Exception

  56. 56 self.assertEqual(is_error(), True)

  57. 57

  58. 58 # mock多个函数,注意函数调用顺序

  59. 59 @patch.object(calculator, 'add')

  60. 60 @patch('mock_learn.multiple')

  61. 61 def test_more(self, mock_multiple, mock_add):

  62. 62 mock_add.return_value = 1

  63. 63 mock_multiple.return_value = 4

  64. 64 self.assertEqual(self.calculator.add(3, 3), 1)

  65. 65 self.assertEqual(multiple(3, 3), 4)

总结:

感谢每一个认真阅读我文章的人!!!

作为一位过来人也是希望大家少走一些弯路,如果你不想再体验一次学习时找不到资料,没人解答问题,坚持几天便放弃的感受的话,在这里我给大家分享一些自动化测试的学习资源,希望能给你前进的路上带来帮助。

  1. 文档获取方式:

  2. 加入我的软件测试交流群:680748947免费获取~(同行大佬一起学术交流,每晚都有大佬直播分享技术知识点)

这份文档,对于想从事【软件测试】的朋友来说应该是最全面最完整的备战仓库,这个仓库也陪伴我走过了最艰难的路程,希望也能帮助到你!

以上均可以分享,只需要你搜索vx公众号:程序员雨果,即可免费领取

相关推荐
belldeep1 小时前
python:reportlab 将多个图片合并成一个PDF文件
python·pdf·reportlab
热爱嵌入式的小许2 小时前
Linux基础项目开发1:量产工具——显示系统
linux·运维·服务器·韦东山量产工具
FreakStudio4 小时前
全网最适合入门的面向对象编程教程:56 Python字符串与序列化-正则表达式和re模块应用
python·单片机·嵌入式·面向对象·电子diy
丶21364 小时前
【CUDA】【PyTorch】安装 PyTorch 与 CUDA 11.7 的详细步骤
人工智能·pytorch·python
_.Switch5 小时前
Python Web 应用中的 API 网关集成与优化
开发语言·前端·后端·python·架构·log4j
一个闪现必杀技5 小时前
Python入门--函数
开发语言·python·青少年编程·pycharm
小鹿( ﹡ˆoˆ﹡ )5 小时前
探索IP协议的神秘面纱:Python中的网络通信
python·tcp/ip·php
卷心菜小温6 小时前
【BUG】P-tuningv2微调ChatGLM2-6B时所踩的坑
python·深度学习·语言模型·nlp·bug
韩楚风6 小时前
【linux 多进程并发】linux进程状态与生命周期各阶段转换,进程状态查看分析,助力高性能优化
linux·服务器·性能优化·架构·gnu
陈苏同学6 小时前
4. 将pycharm本地项目同步到(Linux)服务器上——深度学习·科研实践·从0到1
linux·服务器·ide·人工智能·python·深度学习·pycharm