mock应用
1.使用mock模拟返回值
python
#model.py
class Count():
def add(self,a,b):
return a+b
python
#test_demo_01.py
import unittest
from unittest import mock
from unittest_04.model import Count
class MockDemo(unittest.TestCase):
def test_add(self):
count = Count()
#由mock数据来构成返回值,也就是不需要传递参数就可以规定当前的返回值为16了
count.add = mock.Mock(return_value=16)
#此处正常调用add()方法,不要传递参数,如果成功则说明mock数据生效了
self.assertEqual(count.add(), 16)
if __name__ == '__main__':
unittest.main()
2.class Mock的参数
上面讲的是mock对象最基本的用法。下面来看看mock对象的稍微高级点的用法(并不是很高级啊,最完整最高级的直接去看mock的文档即可,后面给出)。
先来看看Mock这个类的参数,在上面看到的类定义中,我们知道它有好几个参数,这里介绍最主要的几个:
- name: 这个是用来命名一个mock对象,只是起到标识作用,当你print一个mock对象的时候,可以看到它的name。
- return_value: 这个我们刚才使用过了,这个字段可以指定一个值(或者对象),当mock对象被调用时,如果side_effect函数返回的是DEFAULT,则对mock对象的调用会返回return_value指定的值。
- side_effect: 这个参数指向一个可调用对象,一般就是函数。当mock对象被调用时,如果该函数返回值不是DEFAULT时,那么以该函数的返回值作为mock对象调用的返回值。
注意:如果side_effect和return_value同时存在的时候,side_effect会把return_value覆盖掉
python
from unittest import mock
import unittest
class Person():
def __init__(self):
self.age = 10
self.name = "哈利波特"
def get_age(self):
return self.age
def get_name(self,first_name):
return first_name+self.name
def get_sp_name(self):
return "snow"
class MockDemo(unittest.TestCase):
def test_demo01(self):
p = Person()
#这里有坑,上面说的注意,两行代码对比着看一下,side_effect指定的是方法,也就是说要把这个方法提供的内容当做mock的结果这个方法是:p.get_sp_name
p.get_name = mock.Mock(return_value="伏地魔",side_effect=p.get_sp_name)
# p.get_name = mock.Mock(return_value="伏地魔")
self.assertEqual(p.get_name(),"snow")
if __name__ == '__main__':
unittest.main()
3.使用side_effect, 依次返回指定值
python
class MockDemo(unittest.TestCase):
def test_demo01(self):
p = Person()
p.get_age = mock.Mock(side_effect=[10,11])
self.assertEqual(p.get_age(),10)
self.assertEqual(p.get_age(),11)
p.get_name = mock.Mock(side_effect=['snow',"lee"])
self.assertEqual(p.get_name(),"snow")#没问题
self.assertEqual(p.get_name(),"snow")#会报错
注意:以此执行的时候会按照list提供的值的顺序来完成
4. 根据参数不同,返回不同的值
python
class MockDemo(unittest.TestCase):
def test_demo01(self):
p = Person()
values = {("李"):"熊大",("王"):"熊二"}
#这里有坑,首先lambda表达式需要参数"x",第二side_effect需要通过函数来mock,不是简单的返回值
p.get_name = mock.Mock(side_effect=lambda x:values.get("李"))
#坑在这里,p.get_name("这里要用参数,不用就报错"),参数是什么无所谓
self.assertEqual(p.get_name("abc"),"熊大")
5. 检查调用情况
python
class MockDemo(unittest.TestCase):
def test_demo01(self):
p = Person()
p.get_name = mock.Mock(return_value="伏地魔")
self.assertEqual(p.get_name(),"伏地魔")
# 已经被调用过了,如果没有被调用过则抛出异常,注意位置
# p.get_name.assert_called()
# 还没有被调用过,如果被调用过则抛出异常
# p.get_name.assert_not_called()
# 只调用一次,调用过多次就报错
# p.get_name.assert_called_once()
# p.get_name("伏地魔")
# 这里要注意,只能调用一次,且方法需要传递参数,而且需要调用普通方法来完成,之前的self.assertEqual(p.get_name(),"伏地魔")不能存在
# p.get_name.assert_called_once_with("伏地魔")
# p.get_name("伏地魔")
# 调用过就可以,如果有参数的话,必须一致
# p.get_name.assert_any_call("伏地魔")
# 重置mock
p.get_name.reset_mock()
# 果然被重置过,报错了
p.get_name.assert_called()