Python中的模块学习之mock模块
python mock官方文档https://docs.python.org/3/library/unittest.mock.html#unittest.mock.Mock.side_effect
*args, **kwargs的理解;
side_effect
This can either be a function to be called when the mock is called, an iterable or an exception (class or instance) to be raised.
If you pass in a function it will be called with same arguments as the mock and unless the function returns the DEFAULT singleton the call to the mock will then return whatever the function returns. If the function returns DEFAULT then the mock will return its normal value (from the return_value).
If you pass in an iterable, it is used to retrieve an iterator which must yield a value on every call. This value can either be an exception instance to be raised, or a value to be returned from the call to the mock (DEFAULT handling is identical to the function case).
An example of a mock that raises an exception (to test exception handling of an API):
>>>
>>> mock = Mock()
>>> mock.side_effect = Exception('Boom!')
>>> mock()
Traceback (most recent call last):
...
Exception: Boom!
Using side_effect to return a sequence of values:
>>>
>>> mock = Mock()
>>> mock.side_effect = [3, 2, 1]
>>> mock(), mock(), mock()
(3, 2, 1)
Using a callable:
>>>
>>> mock = Mock(return_value=3)
>>> def side_effect(*args, **kwargs):
... return DEFAULT
...
>>> mock.side_effect = side_effect
>>> mock()
3
side_effect can be set in the constructor. Here’s an example that adds one to the value the mock is called with and returns it:
>>>
>>> side_effect = lambda value: value + 1
>>> mock = Mock(side_effect=side_effect)
>>> mock(3)
4
>>> mock(-8)
-7
Setting side_effect to None clears it:
>>>
>>> m = Mock(side_effect=KeyError, return_value=3)
>>> m()
Traceback (most recent call last):
...
KeyError
>>> m.side_effect = None
>>> m()
3
>>> values = {'a': 1, 'b': 2, 'c': 3}
>>> def side_effect(arg):
... return values[arg]
...
>>> mock.side_effect = side_effect #左边side_effect表示的事mock对象具有side_effect的属性
# 右边 side_effect表示外部定义的side_effect方法,它的输入arg是根据mock的方法的输入保持一致的;
>>> mock('a'), mock('b'), mock('c')
(1, 2, 3)
>>> mock.side_effect = [5, 4, 3, 2, 1]
>>> mock(), mock(), mock()
(5, 4, 3)
from __future__ import absolute_import
from mock import mock
#mock 的基本原理,用myremove去模拟系统自带的os.remove类方法。
import os
def myremove(filename):
return filename
os.remove = myremove
print(type(os.remove)) #<class 'function'>
print(type(myremove)) #<class 'function'>
print (os.remove(myremove('test-file')))
#mock一个函数
from mock import Mock
myMethod = Mock()
print(myMethod) #<Mock id='1069934098472'>
print(type(myMethod)) #<class 'mock.mock.Mock'>
myMethod.return_value = 3
myMethod(1,'a',foo ='bar')
myMethod.assert_called_with(1,'a',foo='bar')
myMethod()
print(myMethod.call_count) # myMethod(1,'a',foo ='bar'),myMethod(),调用2次。
#mock用side_effect
def side_effect(str):
return len(str)
print(Mock.side_effect) #<property object at 0x0000003F7FFA8EA8>
print(type(Mock.side_effect)) #<class 'property'>
myMethod = Mock(side_effect=side_effect) #myMethod被Mock了,并且Mock的方式是用的side_effect的方式。
print(myMethod('sd'))#2
print(myMethod('fgsd')) #4,不同的输入有不同的输出,而return_value则一直是一个输出。
class Module1(object):
class Class1(object):
def some_method(self,*args,**Kwargs):
return 'learn_mock'
#mock一个类方法
import mock
import mock
# def mock_patch_object(Module1,method):
# pass
import mock.mock as _mock
from mock.mock import *
__all__ = _mock.__all__
from unittest import TestCase
from unittest.mock import patch
from unittest import main
@mock_patch_object(Module1.Class1,'some_method') #mock_patch_object导入不成功????
def test(mock_method):
mock_method.return_value = 3
def some_side_effect(*args):
return 11
mock_method.side_effect = some_side_effect
m = Module1.Class1()
m.some_method('hah',1)
print(m.some_method('hah',1))
##########
#延伸mock.Mock(return_value=mock_result)是一个对象,但为什么system_b.send_request = mock.Mock(return_value=mock_result)返回的是数据而不是对象的其他属性跟方法呢,在这里,是因为mock对象中有一个side_effect属性,如果这个属性为None,就会将return_value设置的值返回。
##项目中mock的理解
@mock.patch.object(ModelDescribeSvc, 'get_describe')
@mock.patch.object(EvaluateSvc, 'evaluate_by_features')
@mock.patch.object(EvaluateSvc, 'evaluate_by_prob')
@mock.patch.object(CompaniesFeaturesSvc, 'get_features_by_company_name_maybe')
@mock.patch.object(CompaniesFeaturesSvc, 'add_or_update_features')
@mock.patch.object(CompaniesFeaturesSvc, 'delete_by_company_name')
@mock.patch.object(RemarkCompanyListDbSvc, 'find_prob_maybe_by_company_name')
@mock.patch.object(FeatureDealSvc, 'get_feature')
def test_get_model_risk_result(
self, get_feature, find_prob_maybe_by_company_name, delete_by_company_name,
add_or_update_features, get_features_by_company_name_maybe, evaluate_by_prob,
evaluate_by_features, get_describe
):
"""
采用-数据库黑白名单部分产生-预测
"""
# -- given
biz_svc = BizController()
company_name = u'重庆嘉禾一品餐饮管理有限公司'
cancel_rate = 0.5
# mocks
get_feature.return_value = self._get_feature_deal_do(BizConsts.ENTERPRISE_CODE_NORMAL, BizConsts.SAIC_NORMAL)
find_prob_maybe_by_company_name.return_value = Maybe.some(DataConsts.CANCEL_PROB_KNOWN_BLACK)
add_or_update_features.return_value = None
get_features_by_company_name_maybe.return_value = Maybe.none()
get_describe.return_value = u'风险文字描述'
delete_by_company_name.return_value = None
evaluate_by_features.return_value = EvaluateDto(revoke_prob=cancel_rate, risk_rank=BizConsts.RISK_RANK_HIGH)
self.__assert_fake_predict(biz_svc, company_name, cancel_rate, evaluate_by_prob) #传入参数和mock的方法
def __assert_fake_predict(self, biz_svc, company_name, cancel_rate, evaluate_by_prob_func):
"""
采用-数据库黑白名单部分产生-预测
"""
# -- given
self.verify_revoke_prob = None
def evaluate_by_prob_side_effect(*arg):
self.verify_revoke_prob = arg[1]
return EvaluateDto(revoke_prob=cancel_rate)
evaluate_by_prob_func.side_effect = evaluate_by_prob_side_effect #等号左边是因为mock的方法有side_effect这个属性,这个属性具有哪些特征呢?
#side_effect的特点:可以屏蔽return_value,
# -- when
risk_res = biz_svc.get_model_risk_result(company_name, False)
# -- then
self.t_u.assert_equal(BizConsts.OUTPUT_STATUS_HUMAN_INTERVENTION, risk_res.status_code)
self.t_u.assert_equal(BizConsts.OUTPUT_STATUS_HUMAN_INTERVENTION_MESSAGE, risk_res.status_message)
self.t_u.assert_equal(DataConsts.CANCEL_PROB_KNOWN_BLACK, self.verify_revoke_prob)
assert risk_res.evaluate_dto