Python 测试中 Mock 的使用指南:从概念到实战
本文详解 Python 中 Mock 模块的概念与应用场景,涵盖前端与后端接口测试中的模拟策略。深入解析 Mock 类的核心参数 spec、side_effect、return_value 及 name,并通过简单与完整测试案例演示如何拦截依赖、处理异常及验证返回值。同时介绍 unittest 中常用的断言方法,帮助开发者高效进行依赖隔离测试。
Mock 概念
Mock 的核心含义是模拟,即通过预设的固定信息来替代接口实际返回的数据,从而实现对依赖模块的独立测试。
在实际开发中,Mock 主要应用于两种典型场景:
- 前端对后端接口的数据模拟,
- 后端服务之间交互时的测试,这通常发生在单元测试阶段。
前端实现 Mock 可借助多种工具:
- 利用抓包工具如 Fiddler 或 Charles,通过修改代理服务器返回的数据,以覆盖多种测试场景。
- 使用 API 管理工具进行模拟,例如 yapi、Easy Mock 等。
- 具备编码能力的开发者,也可使用 Node.js 或 Python 的 FastAPI 自行构建模拟服务。
后端 Mock 则侧重于接口层面的依赖处理。在敏捷开发中,若接口 A 的返回数据依赖于尚未开发完成的接口 B,此时需使用 Mock 模拟接口 B 的响应。
对于测试人员而言,在接口定义已明确但部分接口尚未开发完成的情况下,也可通过 Mock 进行接口测试。
在 Python 3.X 版本中,Mock 模块已内置集成于 unittest 库中。
Mock 类
class Mock(spec=None,side_effect=None,return_value=DEFAULT,name=None)
- spec:用于定义 Mock 对象的属性值,可以是列表、字符串或某个对象的实例。
- side_effect:用于抛出异常或动态改变返回值,其优先级高于 return_value。
- return_value:用于定义 Mock 对象的固定返回值。
- name:作为 Mock 对象的标识符,在打印输出时可见。
通过简单示例体验 Mock 的功能特点
from unittest import mock
def add(num1,num2):
return num1 + num2 # pass
add = mock.Mock(return_value=200) # 创建mock对象
print( add(10,20) )
无论输入何种参数,输出结果始终为 200。这表明方法已被 Mock 拦截并直接返回预设值。
一个相对正式的 Mock 测试案例
正常情况下的代码逻辑:
import requests
def request_scm():
# res = requests.get('http://www.mysx-scm.com')
res = requests.get('http://baidu.com')
return res.status_code
import unittest
from unittest import mock
class TestScmApi(unittest.TestCase):
def testUrl(self):
# request_scm = mock.Mock(return_value=200)
self.assertEqual(request_scm(), 200, msg='testUrl 出现错误')
if __name__ == '__main__':
unittest.main()
读者可尝试将两处注释符号移至下一行代码处,以观察不同 Mock 配置下的行为差异。
一个完整的测试案例
import requests
class scmapi():
def request_scm():
res = requests.get('http://www.mysx-scm.com')
# res = requests.get('http://baidu.com')
return res.status_code
def pay_alipay():
'''
待实现
return 200
'''
return 0
import unittest
from unittest import mock
class TestScmApi(unittest.TestCase):
needmock = True
def setUpClass():
print("setUpClass():所有方法之前执行")
def tearDownClass():
print("tearDownClass():所有方法之后执行")
def setUp(self):
self.scmapi = scmapi()
print("setUp():每个方法之前执行")
def tearDown(self):
print("teardown():每个方法之后执行")
def test_request_scm(self):
if self.needmock:
scmapi.request_scm = mock.Mock(return_value=200)
self.assertEqual(scmapi.request_scm(), 200, msg='test_request_scm 出现错误')
def test_pay_alipay(self):
if self.needmock:
scmapi.pay_alipay = mock.Mock(return_value=200)
self.assertEqual(scmapi.pay_alipay(), 200, msg='test_pay_alipay 出现错误')
if __name__ == '__main__':
unittest.main()
断言方法
基本的断言方法用于判断测试结果是否为 True 或 False。所有断言方法均支持 msg 参数,若指定该参数,失败时将返回指定的错误信息。
| 序号 | 断言方法 | 断言描述 |
|---|---|---|
| 1 | assertEqual(arg1, arg2, msg=None) | 验证arg1=arg2,不等则fail |
| 2 | assertNotEqual(arg1, arg2, msg=None) | 验证arg1 != arg2, 相等则fail |
| 3 | assertTrue(expr, msg=None) | 验证expr是true,如果为false,则fail |
| 4 | assertFalse(expr,msg=None) | 验证expr是false,如果为true,则fail |
| 5 | assertIs(arg1, arg2, msg=None) | 验证arg1、arg2是同一个对象,不是则fail |
| 6 | assertIsNot(arg1, arg2, msg=None) | 验证arg1、arg2不是同一个对象,是则fail |
| 7 | assertIsNone(expr, msg=None) | 验证expr是None,不是则fail |
| 8 | assertIsNotNone(expr, msg=None) | 验证expr不是None,是则fail |
| 9 | assertIn(arg1, arg2, msg=None) | 验证arg1是arg2的子串,不是则fail |
| 10 | assertNotIn(arg1, arg2, msg=None) | 验证arg1不是arg2的子串,是则fail |
| 11 | assertIsInstance(obj, cls, msg=None) | 验证obj是cls的实例,不是则fail |
| 12 | assertNotIsInstance(obj, cls, msg=None) | 验证obj不是cls的实例,是则fail |
以上即为 Python 测试中使用 Mock 的详细内容,更多关于 Python 测试中 Mock 的资料请关注本站其它相关文章!
本站声明
本文内容仅供参考,不代表本站观点。转载或引用请注明出处。如发现内容问题,请通过联系我们页面反馈。













