Skip to content

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()