模拟函数参数名称以与inspect.getargspec一起使用

时间:2015-08-06 14:26:41

标签: python python-2.7 inspect python-mock

我正在尝试为最终通过inspect.getargspec函数传递模拟的测试模拟函数。我想使用一些特定的名称作为模拟函数的参数名称。

据我所知,没有特定的方法来模拟参数名称,所以我试图使用Mock的spec=参数:

In [1]: import mock, inspect

In [2]: inspect.getargspec(mock.Mock(spec=lambda a,b:None))
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
<ipython-input-2-de358c5a968d> in <module>()
----> 1 inspect.getargspec(mock.Mock(spec=lambda a,b:None))

/usr/lib/python2.7/inspect.pyc in getargspec(func)
    815     if not isfunction(func):
    816         raise TypeError('{!r} is not a Python function'.format(func))
--> 817     args, varargs, varkw = getargs(func.func_code)
    818     return ArgSpec(args, varargs, varkw, func.func_defaults)
    819 

/usr/lib/python2.7/inspect.pyc in getargs(co)
    750 
    751     if not iscode(co):
--> 752         raise TypeError('{!r} is not a code object'.format(co))
    753 
    754     nargs = co.co_argcount

TypeError: <Mock name='mock.func_code' id='140395908951120'> is not a code object

所以,是的,确实,Mock不是代码对象。如何模拟参数名称以便inspect.getargspec返回这些名称?

3 个答案:

答案 0 :(得分:2)

您可以改为修补inspect.getargspec

getargspec_orig = inspect.getargspec
def getargspec_patch(f):
    if f == <your function>:
        return ArgSpec(args=[...], varargs=..., keywords=..., defaults=(...))
    else:
        return getargspec_orig(f)

with patch('inspect.getargspec', new_callable=getargspec_patch):
    # do your testing here

答案 1 :(得分:1)

一个简单的解决方案是使用正确的模拟函数而不是mock.Mock实例。如果您需要对Mock实例进行调用跟踪并隐式创建Mock实例作为返回值,您只需在模拟函数中调用此类实例:

def test_something(self):
    mock_instance = mock.Mock()
    def mock_callback(a, b):
        return mock_instance(a, b)
    result = function_to_test(mock_callback)
    self.assertEqual(mock_instance.call_count, 3)

如果您需要在多个函数中进行回调(或者由于其他原因不希望它成为本地函数),您可以编写一个返回回调和Mock实例的工厂函数:

def make_mock_callback():
    mock_instance = mock.Mock()
    def mock_callback(a, b):
        return mock_instance(a, b)
    return mock_instance, mock_callback

通过关闭mock_instance,您可以确保每个回调都有自己的Mock,而不会污染函数的原型。

答案 2 :(得分:1)

管理以找到几乎不会受到伤害的解决方法。因此,请按照问题文本中的示例:

In [1]: import mock, inspect

定义spec函数(分配给标识符,因为我以后需要它两次):

In [2]: specfun = lambda a,b: None

定义模拟。做了一些实验后,我注意到inspect.getargspec只需要一个func_code对象:

In [3]: mockfun = mock.Mock(spec=specfun, func_code=specfun.func_code)

是否适用于inspect.getargspec?是的!

In [4]: inspect.getargspec(mockfun)
Out[4]: ArgSpec(args=['a', 'b'], varargs=None, keywords=None, defaults=<Mock name='mock.func_defaults' id='140160757665168'>)

它是否像普通的可调用模拟一样工作?是的!

In [5]: mockfun('hello', 42)
Out[5]: <Mock name='mock()' id='140160757483984'>

In [6]: mockfun.call_args_list
Out[6]: [call('hello', 42)]