diff options
author | Xtreak <tir.karthi@gmail.com> | 2019-08-29 06:09:01 (GMT) |
---|---|---|
committer | Chris Withers <chris@withers.org> | 2019-08-29 06:09:01 (GMT) |
commit | c96127821ebda50760e788b1213975a0d5bea37f (patch) | |
tree | 24caeafdabdb90de9234c33134882d227b883a4a /Lib/unittest/mock.py | |
parent | 03acba6f1a851064ba1fa78965ece4354d499c04 (diff) | |
download | cpython-c96127821ebda50760e788b1213975a0d5bea37f.zip cpython-c96127821ebda50760e788b1213975a0d5bea37f.tar.gz cpython-c96127821ebda50760e788b1213975a0d5bea37f.tar.bz2 |
bpo-36871: Ensure method signature is used when asserting mock calls to a method (GH13261)
* Fix call_matcher for mock when using methods
* Add NEWS entry
* Use None check and convert doctest to unittest
* Use better name for mock in tests. Handle _SpecState when the attribute was not accessed and add tests.
* Use reset_mock instead of reinitialization. Change inner class constructor signature for check
* Reword comment regarding call object lookup logic
Diffstat (limited to 'Lib/unittest/mock.py')
-rw-r--r-- | Lib/unittest/mock.py | 36 |
1 files changed, 35 insertions, 1 deletions
diff --git a/Lib/unittest/mock.py b/Lib/unittest/mock.py index 298b41e..5846eeb 100644 --- a/Lib/unittest/mock.py +++ b/Lib/unittest/mock.py @@ -804,6 +804,35 @@ class NonCallableMock(Base): return message % (action, expected_string, actual_string) + def _get_call_signature_from_name(self, name): + """ + * If call objects are asserted against a method/function like obj.meth1 + then there could be no name for the call object to lookup. Hence just + return the spec_signature of the method/function being asserted against. + * If the name is not empty then remove () and split by '.' to get + list of names to iterate through the children until a potential + match is found. A child mock is created only during attribute access + so if we get a _SpecState then no attributes of the spec were accessed + and can be safely exited. + """ + if not name: + return self._spec_signature + + sig = None + names = name.replace('()', '').split('.') + children = self._mock_children + + for name in names: + child = children.get(name) + if child is None or isinstance(child, _SpecState): + break + else: + children = child._mock_children + sig = child._spec_signature + + return sig + + def _call_matcher(self, _call): """ Given a call (or simply an (args, kwargs) tuple), return a @@ -811,7 +840,12 @@ class NonCallableMock(Base): This is a best effort method which relies on the spec's signature, if available, or falls back on the arguments themselves. """ - sig = self._spec_signature + + if isinstance(_call, tuple) and len(_call) > 2: + sig = self._get_call_signature_from_name(_call[0]) + else: + sig = self._spec_signature + if sig is not None: if len(_call) == 2: name = '' |