Karthikeyan Singaravelan <tir.kar...@gmail.com> added the comment:

Using spec only checks for the attribute to be present and not the signature of 
the actual attribute being called. You might need autospec for this behavior. 
The below example to use create_autospec does the correct validation for 
mock_foo.func. There is an open issue to make spec also do signature validation 
but it could go into 3.9 only if accepted since it changes semantics : 
issue30587. Regarding the error message being cryptic there are other issues 
open on assertion error being displayed with actual and expected call list 
being same. I would propose closing this issue. Maybe the docs could be updated 
about this behavior to make sure using spec is more clear on the expected 
behavior.

https://docs.python.org/3/library/unittest.mock.html#unittest.mock.Mock

spec: This can be either a list of strings or an existing object (a class or 
instance) that acts as the specification for the mock object. If you pass in an 
object then a list of strings is formed by calling dir on the object (excluding 
unsupported magic attributes and methods). Accessing any attribute not in this 
list will raise an AttributeError.

# bpo25312.py

from unittest.mock import call, create_autospec, Mock
import inspect

class Foo:

    def __init__(self, val):
        pass

    def func(self):
        pass

class FooMock(Mock):

    def _get_child_mock(self, **kwargs):
        return create_autospec(Foo)

mock_foo = FooMock()
print(inspect.signature(mock_foo.func)) # Signature is correct with 
create_autospec whereas with Mock(spec=Foo) it is (*args, **kwargs)
mock_foo.func() # Raises TypeError with (val) being signature.
mock_foo.func.assert_has_calls([call()])


➜  cpython git:(master) ✗ ./python.exe bpo25312.py
(val)
Traceback (most recent call last):
  File "/Users/karthikeyansingaravelan/stuff/python/cpython/bpo25312.py", line 
19, in <module>
    mock_foo.func()
  File 
"/Users/karthikeyansingaravelan/stuff/python/cpython/Lib/unittest/mock.py", 
line 1027, in __call__
    self._mock_check_sig(*args, **kwargs)
  File 
"/Users/karthikeyansingaravelan/stuff/python/cpython/Lib/unittest/mock.py", 
line 119, in checksig
    sig.bind(*args, **kwargs)
  File "/Users/karthikeyansingaravelan/stuff/python/cpython/Lib/inspect.py", 
line 3025, in bind
    return self._bind(args, kwargs)
  File "/Users/karthikeyansingaravelan/stuff/python/cpython/Lib/inspect.py", 
line 2940, in _bind
    raise TypeError(msg) from None
TypeError: missing a required argument: 'val'

----------
nosy: +cjw296, mariocj89
versions: +Python 3.7, Python 3.8, Python 3.9 -Python 3.4, Python 3.5, Python 
3.6

_______________________________________
Python tracker <rep...@bugs.python.org>
<https://bugs.python.org/issue25312>
_______________________________________
_______________________________________________
Python-bugs-list mailing list
Unsubscribe: 
https://mail.python.org/mailman/options/python-bugs-list/archive%40mail-archive.com

Reply via email to