1. 什么是Mock测试
mock测试就是在测试过程中,对于某些不容易构造或者不容易获取的对象/数据/场景,用一个虚拟的对象来创建以便测试的测试方法。
2. Mock测试常见场景
- 无法控制第三方系统接口的返回,返回的数据不满足要求
- 依赖的接口还未开发完成,就需要对被测系统进行测试
3. Mock测试的优缺点
优点:
- 团队可以并行工作,只要双方定义好接口,及接口数据规范,即可使用Mock构建出虚拟接口然后尽快进行开发和自测,以满足测试前移要求,也有利提早发现缺陷
- 测试驱动开发TDD,通过利用Mock使测试人员提前接入测试从而达到测试驱动开发的效果
- 提高测试覆盖率,通过Mock模拟一些业务逻辑复杂或无法通过正常手段进行操作的场景从而提高测试的覆盖率
- 隔离测试环境与数据库环境,保证数据库的纯净
缺点:
- 如果在测试过程中大量使用Mock,Mock测试的场景失去真实性,可能会导致在后续的系统性测试时才发现缺陷,使得缺陷发现得比较晚,造成后续修复成本大的严重后果
4. Python中的Mock库
很多语言现在都有Mock库,方便在单元测试时进行Mock测试,下面主要介绍Mock在Python中的使用
4.1 安装Mock库
pip install Mock
4.2 Mock在Python中的使用
# case1
import unittest
from mock import Mock
class SubClass(object):
def add(self,a,b):
"""实现两个数相加"""
pass
class TestSub(unittest.TestCase):
"""测试两个数相加用例"""
def test_sub(self):
sub = SubClass() # 初始化被测函数类实例
sub.add = Mock(return_value=10) # mock add方法 指定返回10
result = sub.add(5,5) # 调用被测函数
self.assertEqual(result,10) # 断言实际结果与预期结果是否一致
if __name__ == "__main__":
unittest.main()
# case2
import unittest
from mock import Mock
class SubClass(object):
def add(self,a,b):
"""实现两个数相加"""
return a + b
class TestSub(unittest.TestCase):
"""测试两个数相加用例"""
def test_sub(self):
sub = SubClass() # 初始化被测函数类实例
sub.add = Mock(return_value=10,side_effect=sub.add) # 传递side_effect关键参数,覆盖return_value参数值,使用真实的add函数进行测试
result = sub.add(5,11) # 调用被测函数
self.assertEqual(result,16) # 断言实际结果与预期结果是否一致
if __name__ == "__main__":
unittest.main()
# case3
import unittest
from mock import Mock
def verifyPhoneNum():
'''
验证手机号
'''
pass
class TestVerifyPhoneNum(unittest.TestCase):
def test_verify_phone_num(self):
data = {"code": "0100","msg": {"result": "Success","Isp": "中国移动"}}
verifyPhoneNum = Mock(return_value=data)
self.assertEqual("Success",verifyPhoneNum()["msg"]["result"])
self.assertEqual("中国移动",verifyPhoneNum()["msg"]["Isp"])
if __name__ == "__main__":
unittest.main()
在case3
的验证手机号中,肯定还会有其他的返回情况,我们可以预先定义好返回结果以供测试(一般接口文档已经有设计好)
# 手机号校验通过
{
"code": "0100",
"msg": {
"result": "Success",
"Isp": "中国移动"
}
}
{
"code": "0101",
"msg": {
"result": "Success",
"Isp": "中国联通"
}
}
{
"code": "0102",
"msg": {
"result": "Success",
"Isp": "中国电信"
}
}
# 手机号格式错误
{
"code": "0200",
"msg": {
"result": "Fail",
"Isp": "",
"errorinfo": "手机号格式错误"
}
}
# 手机号已存在
{
"code": "0300",
"msg": {
"result": "Fail",
"Isp": "",
"errorinfo": "手机号已存在"
}
}
5. 使用Postman进行Mock测试
除了在编程语言上集成Mock,Mock测试还可用工具来进行模拟达到测试目的。
5.1 新建一个Mock Server
1、打开Postman,选中Mock Server项,点Create Mock Server
2、填写Mock Server信息
3、创建成功
4、点击View Collection Docs查看信息
5、点击Open Request,创建一个请求(会自动创建一个Collection),填写必要信息
6、请求结果
6. 用Python访问创建的Mock Server
import unittest
import requests
url = r'https://b129ef27-436a-45f2-8971-9d8674201095.mock.pstmn.io/mock/mockdemo'
data = {
"memberid": "354802185",
"phonenum": "13724312459",
"msg": {
"Country": "中国",
"Province": "广东省",
"City": "深圳市",
"Isp": "中国移动"
},
"type_code": 0
}
header = {
"Content-Type": "application/json",
"token": "91932f295a75a5a743974a0e4b308fc6",
"x-api-key": "PMAK-63d8c41e8b44370ec5b5c595-780df67fc8c748328add9aec0286b89898"
}
class TestMockServer(unittest.TestCase):
respone = requests.get(url=url,headers=header)
result = respone.json()
print(result)
def test_code(self):
self.assertEqual("200",self.result['code'])
def test_result(self):
self.assertEqual('Success',self.result['msg']['result'])
def test_memberinfo(self):
self.assertEqual('白金瀚至臻会员',self.result['msg']['memberinfo'])
def test_membertype(self):
self.assertEqual('666',self.result['msg']['membertype'])
if __name__ == "__main__":
unittest.main()
运行结果:
{'code': '200', 'msg': {'result': 'Success', 'memberinfo': '白金瀚至臻会员', 'membertype': '666'}}
....
----------------------------------------------------------------------
Ran 4 tests in 0.002s
OK
接口路径 /mock/testdemo
请求头
Content-Type application/json
token 91932f295a75a5a743974a0e4b308fc6
请求体
{
"memberid": "354802185",
"phonenum": "13724312459",
"msg": {
"Country": "中国",
"Province": "广东省",
"City": "深圳市",
"Isp": "中国移动"
},
"type_code": 0
}
响应体
{
"code": "200",
"msg": {
"result": "Success",
"memberinfo": "白金瀚至臻会员",
"membertype": "666"
}
}
mock地址:
https://b129ef27-436a-45f2-8971-9d8674201095.mock.pstmn.io
API keys:
PMAK-63d8c41e8b44370ec5b5c595-780df67fc8c748328add9aec0286b89898