什么是mock?比如我们需要用一个接口时,这个接口还没有实现或者依赖第三方服务,为了保证当前功能的开发和测试,就要使用mock模拟接口的功能。
Python中使用mock对象替代指定的Python对象,实现控制模拟对象的行为。mock模块在Python 3.3以后合并到unittest模块中了,可以直接通过导入使用。
Mock基本使用
Mock对象就是mock模块中的一个类的实例,创建后,可以指定返回值并设置所需的属性,也可以断言调用了哪些方法/属性及其参数。
class Mock(spec=None, side_effect=None, return_value=DEFAULT, wraps=None, name=None, spec_set=None, **kwargs)
Mock类主要的几个参数:
- name:命名一个mock对象,只是起到标识作用,可以通过print查看。
- return_value: 定义mock方法的返回值,可以指定一个值(或者对象),当mock对象被调用时,返回return_value指定的值。
- side_effect: 这个参数指向一个可调用对象,接收一个可迭代序列。可以抛出异常或者动态改变值。当传递这个参数的时候return_value 参数就会失效。
from unittest import mock
result1 = mock.Mock(name='mock名称')
print(result1)
mock_value1 = mock.Mock(return_value="返回值1")
print(mock_value1())
mock_value2 = mock.Mock(return_value="返回值2",side_effect= [1,2,3])
print(mock_value2())
print(mock_value2())
print(mock_value2())
Mock 步骤如下:
- 导入 unittest 框架中的 mock
- 找到要替换的对象A,可以是一个类、函数或者类实例
- 实例化mock对象,设置mock对象的行为,比如调用的时候返回的值,被访问成员的时候返回什么值等。
- 使用mock对象替换对象A
- 调用并断言
mock一个未开发的接口
mock一个依赖关系的功能
实际工作中,我们也会遇到这样的场景,测试A模块,然后A模块依赖于B模块的调用,这时就可以借助mock在单元测试中分别测试正常返回和异常返回的情况。
下面是一个访问baidu的功能,visit_baidu()方法依赖send_request的返回结果。
import requests
def send_request(url):
r = requests.get(url)
return r.status_code
def visit_baidu():
url = 'http://www.baidu.com'
return send_request(url)
通过mock,在单元测试中分别测试正常返回和异常返回的情况
from unittest import mock
import unittest
import demo
class TestReq(unittest.TestCase):
def test_request_01(self):
# 实例化mock对象,指定返回值,替换原有对象
demo.send_request = mock.Mock(return_value='200')
print(demo.send_request())
self.assertEqual(demo.visit_baidu(), '200')
def test_request_02(self):
# 实例化mock对象,指定返回值,替换原有对象
demo.send_request = mock.Mock(return_value='404')
print(demo.send_request())
self.assertEqual(demo.visit_baidu(), '404')
if __name__ == '__main__':
unittest.main(verbosity=2)
Mock的高级用法
mock库提供了patch函数来简化mock对象对原对象的替换,该函数会返回一个mock内部的类实例,它可以控制mock的范围,可以作为装饰器或者上下文管理器使用。
mock.patch(target,new = DEFAULT,spec = None,create = False,spec_set = None,autospec = None,new_callable = None,** kwargs )
mock装饰器使用格式
- @patch("module名字.方法名")
- @patch.object(类名, "方法名")
patch作为装饰器,需要把你想模拟的函数写在里面,然后在后面的单元测试案例中为它赋一个具体实例,再用return_value 来指定模拟函数返回的结果。
改造上面的单元测试:
from unittest import mock
import unittest
import demo
class TestReq(unittest.TestCase):
#在测试的参数里对该Mock对象设置一个参数
@mock.patch("demo.send_request")
def test_request_01(self,mock_request):
# 指定一个返回值
mock_request.return_value='200'
self.assertEqual(demo.visit_baidu(), '200')
@mock.patch("demo.send_request")
def test_request_02(self,mock_request):
# 指定一个返回值
mock_request.return_value='404'
self.assertEqual(demo.visit_baidu(), '404')
if __name__ == '__main__':
unittest.main(verbosity=2)
最后:下面是配套学习资料,对于做【软件测试】的朋友来说应该是最全面最完整的备战仓库,这个仓库也陪伴我走过了最艰难的路程,希望也能帮助到你!【100%无套路免费领取】
软件测试面试小程序
被百万人刷爆的软件测试题库!!!谁用谁知道!!!全网最全面试刷题小程序,手机就可以刷题,地铁上公交上,卷起来!
8小时传疯!大厂面试真题全被大佬整理在这个小程序上了!【软件测试,建议收藏】
涵盖以下这些面试题板块:
1、软件测试基础理论 ,2、web,app,接口功能测试 ,3、网络 ,4、数据库 ,5、linux
6、web,app,接口自动化 ,7、性能测试 ,8、编程基础,9、hr面试题 ,10、开放性测试题,11、安全测试,12、计算机基础