模拟函数参数名称以使用 inspect.getargspec
Mocking function argument names to work with inspect.getargspec
我正在尝试模拟一个函数以进行最终通过 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
returns 这些名称?
您可以改为修补 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
一个简单的解决方案是使用适当的模拟函数而不是 mock.Mock
实例。如果您需要 Mock
实例的调用跟踪和 Mock
实例的隐式创建作为 return 值,您可以简单地从模拟函数中调用这样的实例:
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)
如果您需要在多个函数中进行回调(或者出于其他原因不希望它成为本地函数),您可以编写一个 return 同时包含回调和 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
,而不会污染函数的原型。
设法找到一个几乎不会造成伤害的解决方法。因此,按照问题文本中的示例:
In [1]: import mock, inspect
定义规范函数(分配给一个标识符,因为我稍后需要它两次):
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'>)
它是否像普通的可调用 Mock 一样工作?是的!
In [5]: mockfun('hello', 42)
Out[5]: <Mock name='mock()' id='140160757483984'>
In [6]: mockfun.call_args_list
Out[6]: [call('hello', 42)]
我正在尝试模拟一个函数以进行最终通过 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
returns 这些名称?
您可以改为修补 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
一个简单的解决方案是使用适当的模拟函数而不是 mock.Mock
实例。如果您需要 Mock
实例的调用跟踪和 Mock
实例的隐式创建作为 return 值,您可以简单地从模拟函数中调用这样的实例:
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)
如果您需要在多个函数中进行回调(或者出于其他原因不希望它成为本地函数),您可以编写一个 return 同时包含回调和 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
,而不会污染函数的原型。
设法找到一个几乎不会造成伤害的解决方法。因此,按照问题文本中的示例:
In [1]: import mock, inspect
定义规范函数(分配给一个标识符,因为我稍后需要它两次):
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'>)
它是否像普通的可调用 Mock 一样工作?是的!
In [5]: mockfun('hello', 42)
Out[5]: <Mock name='mock()' id='140160757483984'>
In [6]: mockfun.call_args_list
Out[6]: [call('hello', 42)]