这段代码:
import mock
from functools import wraps
def dec(f):
@wraps(f)
def f_2(*args, **kwargs):
pass
return f_2
class Example(object):
def __init__(self):
pass
@dec
def method_1(self, arg):
pass
def method_2(self, arg):
self.method_1(arg)
def test_example():
m = mock.create_autospec(Example)
Example.method_2(m, "hello")
m.method_1.assert_called_once_with("hello")
用 py.test 产生这个错误
def test_example():
m = mock.create_autospec(Example)
> Example.method_2(m, "hello")
example.py:26:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
example.py:20: in method_2
self.method_1(arg)
anaconda2/envs/arctic/lib/python2.7/site-packages/mock/mock.py:1061: in __call__
_mock_self._mock_check_sig(*args, **kwargs)
anaconda2/envs/arctic/lib/python2.7/site-packages/mock/mock.py:227: in checksig
sig.bind(*args, **kwargs)
anaconda2/envs/arctic/lib/python2.7/site-packages/mock/mock.py:95: in fixedbind
return self._bind(args, kwargs)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
self = <funcsigs.Signature object at 0x7f09b8685e10>, args = ('hello',), kwargs = {}, partial = False
def _bind(self, args, kwargs, partial=False):
'''Private method. Don't use directly.'''
arguments = OrderedDict()
parameters = iter(self.parameters.values())
parameters_ex = ()
arg_vals = iter(args)
if partial:
# Support for binding arguments to 'functools.partial' objects.
# See 'functools.partial' case in 'signature()' implementation
# for details.
for param_name, param in self.parameters.items():
if (param._partial_kwarg and param_name not in kwargs):
# Simulating 'functools.partial' behavior
kwargs[param_name] = param.default
while True:
# Let's iterate through the positional arguments and corresponding
# parameters
try:
arg_val = next(arg_vals)
except StopIteration:
# No more positional arguments
try:
param = next(parameters)
except StopIteration:
# No more parameters. That's it. Just need to check that
# we have no `kwargs` after this while loop
break
else:
if param.kind == _VAR_POSITIONAL:
# That's OK, just empty *args. Let's start parsing
# kwargs
break
elif param.name in kwargs:
if param.kind == _POSITIONAL_ONLY:
msg = '{arg!r} parameter is positional only, ' \
'but was passed as a keyword'
msg = msg.format(arg=param.name)
raise TypeError(msg)
parameters_ex = (param,)
break
elif (param.kind == _VAR_KEYWORD or
param.default is not _empty):
# That's fine too - we have a default value for this
# parameter. So, lets start parsing `kwargs`, starting
# with the current parameter
parameters_ex = (param,)
break
else:
if partial:
parameters_ex = (param,)
break
else:
msg = '{arg!r} parameter lacking default value'
msg = msg.format(arg=param.name)
raise TypeError(msg)
else:
# We have a positional argument to process
try:
param = next(parameters)
except StopIteration:
raise TypeError('too many positional arguments')
else:
if param.kind in (_VAR_KEYWORD, _KEYWORD_ONLY):
# Looks like we have no parameter for this positional
# argument
> raise TypeError('too many positional arguments')
E TypeError: too many positional arguments
anaconda2/envs/arctic/lib/python2.7/site-packages/funcsigs/__init__.py:716: TypeError
有什么方法可以测试这段代码的意图吗?如果您删除装饰器,或者如果您将参数设置为 method_1 关键字参数,它会神奇地起作用。我不确定这个错误是在 Mock 本身,还是在 funcsigs 中,但显然有些地方不对劲。有解决方法吗?测试 method_2 调用 method_1 的另一种方法?
我应该提一下,这是模拟 1.3.0。由于某种原因,此代码在 1.0.1 中有效,但我需要使用最新版本的 mock。
更新
这个有效:
def test_example():
m = mock.Mock(spec=Example)
m.method_1 = mock.Mock()
Example.method_2(m, "hello")
m.method_1.assert_called_once_with("hello")
最佳答案
从 mock 1.1.0 开始,框架开始深入检查方法签名。看看 changelog在
Issue #17015: When it has a spec, a Mock object now inspects its signature when matching calls, so that arguments can be matched positionally or by name
现在,如果您将 f2()
签名更改为 def f_2(arg, *args, **kwargs)
,它应该可以工作。
也许这是一个新错误,签名检查无法正确理解调用是否正确(至少兼容)。我认为您可以提交错误并在此处发布票证链接。
作为解决方法,您可以通过添加
从method_1
中删除自动指定
m.method_1 = mock.Mock()
关于python - 在 Python 2.7 中使用装饰方法调用发出模拟,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/34800832/