python mock总结

一、Mock模块


为什么使用mock:
在我看来实际中用到mock的场景:

  • 有个函数,我们不关心他的具体实现细节,只想要他的返回。这时就可以mock这个函数的返回
  • mock对象来模拟一个需要使用的资源(?)
>>> import mock
>>> dir(mock.Mock())
['assert_any_call', 'assert_called', 'assert_called_once', 'assert_called_once_with', 'assert_called_with',
 'assert_has_calls', 'assert_not_called', 'attach_mock', 'call_args', 'call_args_list', 'call_count', 
 'called', 'configure_mock', 'method_calls','mock_add_spec', 'mock_calls', 'reset_mock', 'return_value', 
 'side_effect']

Mock方法

一、Mock的构造器

init是mock对象的构造器,name是mock对象的唯一标识;spec设置的是mock对象的属性,可以是property或者方法,也可以是其他的列表字符串或者其他的python类;return_value设置的是,当这个mock对象被调用的时候,显示出的结果就是return_value的值;side_effect是和return_value是相反的,覆盖了return_value,也就是说当这个mock对象被调用的时候,返回的是side_effect的值,而不是return_value。

1、name

# name 是这个Mock实例的唯一标识 ,id是什么?内存,还是实例的编号?
>>> a = mock.Mock(name='name_1')
>>> print a
<Mock name='name_1' id='139821809679056'>

2、 return_value

(a)、return_value指定的是某个值

# 这个b可以是函数名(add),类的函数名(Person.add) 
# b应该是类的实例,可是b()返回 return_value,这个是怎么实现的?
>>> b = mock.Mock(name='name_3', return_value=100)
>>> b
<Mock name='name_3' id='139821809217744'>
>>> print b()
100
>>> print type(b)
<class 'mock.mock.Mock'>

(b)、return_value指定的是类的实例

import unittest
import mock
class Person():
        arg_0 =5
        def __init__(self):
                self.arg_1 = 10
                pass
        def add(self):
                return 20
p = Person()
mock_obj = mock.Mock(return_value=p)
a = mock_obj()

# mock_obj = mock.Mock() 只是返回一个mock实例
# 要他的返回值时a  = mock_obj (),a就是return_value
print 'a: ',a
>>>a:  <__main__.Person instance at 0xd46a28>
print 'a.add: ',a.add
>>>a.add:  <bound method Person.add of <__main__.Person instance at 0xd46a28>>
print 'a.add(): ',a.add()
>>>a.add():  20
print 'a.arg_1: ',a.arg_1
>>>a.arg_1:  10
print a.arg_0
>>>5

3、side_effect参数:

(a)、指定的参数的值是异常

# 返回的异常覆盖了return_value
>>> import mock
>>> import unittest
>>> mock_object = mock.Mock(return_value=10, side_effect=StandardError)
>>> b = mock_object()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/usr/lib/python2.7/site-packages/mock/mock.py", line 1062, in __call__
    return _mock_self._mock_call(*args, **kwargs)
  File "/usr/lib/python2.7/site-packages/mock/mock.py", line 1118, in _mock_call
    raise effect
StandardError

(b)、指定的参数的值是一个list或者tuple:
这个就不展开写了,目前我还没用到

二、Mock实现的例子


  1. Mock一个函数。
    根据上面理解的Mock,可以这么实现:
import unittest
import mock
def multiple(a, b):
        return a*b
class TestProducer(unittest.TestCase):
        def setUp(self):
                pass
        def test_multiple(self):
                multiple = mock.Mock(return_value=3)
                self.assertEqual(multiple(8, 14), 3)

if __name__ == "__main__":
        unittest.main()

另一种方法就是mock.patch

# 为啥执行报错???
# TypeError: Need a valid target to patch. You supplied: 'multiple'
# mock.patch('multiple') 修改为mock.patch('__main__.multiple')
import unittest
import mock

class Calculator(object):
        def add(self, a, b):
                return a+b

def multiple(a, b):
        return a*b
        
class TestProducer(unittest.TestCase):
        def setUp(self):
                self.calculator = Calculator()
        # mock.patch('multiple')一定
        # mock_multiple 是不是可以随便命名???
        @mock.patch('multiple')
        def test_multiple(self, mock_multiple):
                mock_multiple.return_value = 3
                self.assertEqual(multiple(8, 14), 3)

if __name__ == "__main__":
        unittest.main()
  1. Mock一个对象里面的方法
# a31.py
def add4(a,b):
        return a+b

class Add():
        def __init__(self):
                pass
        def add5(self,a,b):
                return a+b
import unittest
import mock
from a31 import Add, add4
class Calculator(object):
        def add(self, a, b):
                return a+b
        def add2(self,a, b):
                return a+b
class TestProducer(unittest.TestCase):
        def setUp(self):
                self.calculator = Calculator()
        @mock.patch.object(Calculator, 'add')
        def test_add(self, mock_add):
                mock_add.return_value = 3
                self.assertEqual(self.calculator.add(8, 14), 3)
         # mock.patch 必须完整的路径
        @mock.patch('__main__.Calculator.add2')
        def test_add2(self,mock_add2):
                mock_add2.return_value = 10
                self.assertEqual(self.calculator.add2(10,20),10)

	# from a31 import Add, add4
	# @mock.patch('__main__.Calculator.add2') 也可以
        @mock.patch('a31.Add.add5')
        def test_add3(self,mock_add5):
                ab = Add()
                mock_add5.return_value = 10
                self.assertEqual(ab.add5(10,20),10)
        @mock.patch('__main__.add4')
        def test_add3(self,mock_add4):
                #ab = Add()
                mock_add4.return_value = 10
                self.assertEqual(add4(10,20),10)

if __name__ == "__main__":
        unittest.main()
# 如果是
import a31
        @mock.patch('a31.Add.add5')
        def test_add3(self,mock_add5):
                ab = a31.Add()
                mock_add5.return_value = 10
                self.assertEqual(ab.add5(10,20),10)
                
        @mock.patch('a31.add4')
        def test_add3(self,mock_add4):
                #ab = Add()
                mock_add4.return_value = 10
                self.assertEqual(a31.add4(10,20),10)

总结:

  1. patch和patch.object,一定要指定mock对象的具体位置。
  2. patch,方法和类都可以mock。方法和类在同一个文件中时要加__main__.
    如@mock.patch(’_ main_.add4’)
  3. mock.patch.object(a31.Add, ‘add5’)应该是只可以mock类中的方法。第一个参数指定类的位置,第二个参数指定类中的方法。
# 函数参数mock_add4只是形参,实际入参是add4。所以 mock_add4可以随便写什么。
# 但最好还是和要mock的函数一致,便于认识。
 @mock.patch('a31.add4')
def test_add3(self,mock_add4): 
	print mock_add4
	
# 输出..<MagicMock name='add4' id='38723792'>
  1. 让Mock的函数抛出exception
import os
import mock
import unittest
def is_error():
        try:
                os.mkdir("11")
                return False
        except Exception as e:
                print 'Exception'
                return True
class TestProducer(unittest.TestCase):
        @mock.patch('os.mkdir')
        def test_exception(self, mock_mkdir):
                mock_mkdir.side_effect = Exception
                self.assertEqual(is_error(), True)
if __name__ == '__main__':
        unittest.main()

三、

参考:
https://blog.csdn.net/peiyao456/article/details/77075173
https://blog.csdn.net/younger_china/article/details/72904448
https://www.cnblogs.com/yoyoketang/p/9346660.html

  • 2
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值