Issue41768
Created on 2020-09-12 01:10 by melwitt, last changed 2020-09-18 21:50 by terry.reedy.
| Pull Requests | |||
|---|---|---|---|
| URL | Status | Linked | Edit |
| PR 22209 | open | melwitt, 2020-09-12 01:21 | |
| Messages (2) | |||
|---|---|---|---|
| msg376757 - (view) | Author: (melwitt) * | Date: 2020-09-12 01:10 | |
When async magic method support was added to unittest.mock.Mock to address issue #26467, it introduced a getattr call [1] that causes class properties to be called when the class is used as a mock spec. This caused a problem for a test in my project when running with Python 3.8 where previously the test worked OK with Python 3.6. The test aims to verify that a class instance is not created if the called code path does not access the class property and thus the class will not create a heavy object unless it's needed (lazy create on access via @property). As of Python 3.8, the @property is always called and is called by the mock spec process itself, even though the code path being tested does not access the class @property. Here is a code snippet that illustrates the @property calling from the mock spec alone: class SomethingElse(object): def __init__(self): self._instance = None @property def instance(self): if not self._instance: self._instance = 'object' ... def test_property_not_called_with_spec_mock(self): obj = SomethingElse() self.assertIsNone(obj._instance) mock = Mock(spec=obj) self.assertIsNone(obj._instance) $ ./python -m unittest -v unittest.test.testmock.testmock.MockTest.test_property_not_called_with_spec_mock test_property_not_called_with_spec_mock (unittest.test.testmock.testmock.MockTest) ... FAIL ====================================================================== FAIL: test_property_not_called_with_spec_mock (unittest.test.testmock.testmock.MockTest) ---------------------------------------------------------------------- Traceback (most recent call last): File "/home/vagrant/cpython/Lib/unittest/test/testmock/testmock.py", line 2173, in test_property_not_called_with_spec_mock self.assertIsNone(obj._instance) AssertionError: 'object' is not None [1] https://github.com/python/cpython/blob/fb2718720346c8c7a0ad2d7477f20e9a5524ea0c/Lib/unittest/mock.py#L492 |
|||
| msg377140 - (view) | Author: Terry J. Reedy (terry.reedy) * ![]() |
Date: 2020-09-18 21:50 | |
Without lines numbers, I cannot test which of the two identical asserts failed. Either comments or msg arguments will differentiate. Nor can I run snippets from two different files. Here is a minimal reproducible self-contained code that demonstrates the claim (which I verified on 3.9 and current master).
import unittest
from unittest.mock import Mock
class SomethingElse(object):
def __init__(self):
self._instance = None
@property
def instance(self):
if not self._instance:
self._instance = 'object'
class Test(unittest.TestCase):
def test_property_not_called_with_spec_mock(self):
obj = SomethingElse()
self.assertIsNone(obj._instance, msg='before') # before
mock = Mock(spec=obj)
self.assertIsNone(obj._instance, msg='after') # after
unittest.main()
|
|||
| History | |||
|---|---|---|---|
| Date | User | Action | Args |
| 2020-09-18 21:50:35 | terry.reedy | set | nosy:
+ terry.reedy, michael.foord messages:
+ msg377140 |
| 2020-09-12 01:34:12 | xtreak | set | nosy:
+ xtreak |
| 2020-09-12 01:21:14 | melwitt | set | keywords:
+ patch stage: patch review pull_requests: + pull_request21264 |
| 2020-09-12 01:10:24 | melwitt | create | |
