一.Mock概念
mock 的意思是模拟,也就是模拟接口返回的信息,用已有的信息替换它需要返回的信息,从实现对上级模块的测试。
这里分为两类测试:一类是前端对接口的mock,一类是后端单元测试中涉及的mock
单纯的前端mock可以通过抓包工具Fiddler,Charles实现,通过修改代理返回的数据,实现多种场景的测试。这里在抓包工具之中会解释。
后端的Mock则是从接口的角度,如果一个接口A返回的数据需要依赖于另一个接口B,当敏捷开发中B接口还未开发完全时候这里会需要用到Mock。
在python3.0中mock模块已经被集成到unittest里面。
参考:
https://www.cnblogs.com/fnng/p/5648247.html
参考:https://docs.python.org/3/library/unittest.mock.html
参考:
http://engineroom.trackmaven.com/blog/making-a-mockery-of-python/
二.实现方式
1.借助一个mock服务平台
easymock
2.借助已有的框架
- java ->
- python -> unittest.mock
三.举一个栗子
定义一个Mock类
- class Mock(spec=None,side_effect=None,return_value=DEFAULT,name=None)
- spec:定义Mock对象的属性值,可以是一个列表,字符串,一个对象的实例
- side_effect:可以用来抛出异常或者动态改变返回值,可以覆盖return_value
- return_value:定义mock的返回值
- name:作为mock对象的标识可以在print时候看到
简单的demo
这里我们需要测试的是一个Count类里面的add函数,但是这个函数还没有写出来.
- count
'''这是一个计算类'''
class Count(object):
def add(self):
pass
- test_count
'''这里要测试这个计算类'''
from unittest import mock
import unittest
from API_Mock.count import Count
class TestCount(unittest.TestCase):
def test_add(self):
mycount = Count()
add_value = 13
#这里mock了mycount类里面add函数的返回结果等于13
mycount.add = mock.Mock(return_value=add_value)
#这里相当于正常调用add函数
result = mycount.add(8,5)
#使用断言判断返回的结果是否和mock的相等
self.assertEqual(result,add_value)
if __name__ == '__main__':
unittest.main()
输出结果:
Ran 1 test in 0.000s
OK
Process finished with exit code 0
完成功能部分
- count
'''这是一个计算类'''
class Count(object):
def add(self, a, b):
return a + b
- test_count
'''这里要测试这个计算类'''
from unittest import mock
import unittest
from API_Mock.count import Count
class TestCount(unittest.TestCase):
def test_add(self):
mycount = Count()
add_value = 13
#这里使用side_effect参数覆盖了return_value的结果。
mycount.add = mock.Mock(return_value=add_value , side_effect=mycount.add)
#这里真正调用add方法并打印结果
result = mycount.add(8,8)
print(result)
#检查mock方法是否获得了正确的参数
mycount.add.assert_called_with(8,8)
self.assertEqual(result, 16)
if __name__ == '__main__':
unittest.main()
解决测试依赖
上面只是针对单独的模块进行测试,假设我们测试的A模块需要B模块返回的数据作为前提,如果B模块返回的结果错误,也会导致A模块的测试失败。这里也需要mock来模拟B模块的返回。
1.原先模块
- count
'''这是一个计算类'''
class Count(object):
def add(self, a, b):
return a + b
def mutiply(self,a,b):
return a*b
def add_and_mutiply(self,a,b):
addition = self.add(a,b)
mutiple = self.mutiply(a,b)
return (addition,mutiple)
- test_count
'''这里要测试这个计算类'''
from unittest import mock
import unittest
from API_Mock.count import Count
class TestCount(unittest.TestCase):
def test_add_and_mutiply(self):
mycount = Count()
x = 3
y = 5
addition,mutiple = mycount.add_and_mutiply(x,y)
self.assertEqual(8,addition)
self.assertEqual(15,mutiple)
if __name__ == '__main__':
unittest.main()
2.依赖项缺失
当依赖项缺失的时候,也就是模块B返回错误,这里依然要保证对模块A的测试是正常的。
这里给add函数返回结果+3
class Count(object):
def add(self, a, b):
return a + b+3
所以,会有以下报错
- 报错
Ran 1 test in 0.000s
FAILED (failures=1)
11 != 8
Expected :8
Actual :11
测试用例运行失败,但是实际上模块A并没有任何改动,这里就需要mockB模块
- test_count
'''这里要测试这个计算类'''
from unittest import mock
import unittest
from API_Mock.count import Count
from unittest.mock import patch
class TestCount(unittest.TestCase):
def test_add_and_mutiply(self):
mycount = Count()
x = 3
y = 5
mycount.add = mock.Mock(return_value = 8)
addition,mutiple = mycount.add_and_mutiply(x,y)
mycount.add.assert_called_with(3,5)
self.assertEqual(8,addition)
self.assertEqual(15,mutiple)
if __name__ == '__main__':
unittest.main()