This issue tracker has been migrated to GitHub ,
and is currently read-only.
For more information,
see the GitHub FAQs in the Python's Developer Guide.
Created on 2017年06月01日 20:16 by mariocj89, last changed 2022年04月11日 14:58 by admin. This issue is now closed.
| Pull Requests | |||
|---|---|---|---|
| URL | Status | Linked | Edit |
| PR 1923 | merged | mariocj89, 2017年06月02日 19:49 | |
| PR 5107 | merged | p-ganssle, 2018年01月05日 17:42 | |
| Messages (11) | |||
|---|---|---|---|
| msg294961 - (view) | Author: Mario Corchero (mariocj89) * (Python triager) | Date: 2017年06月01日 20:16 | |
Define a way to disable the automatic generation of submocks when accessing an attribute of a mock which is not set. Rationale: Inspired by GMock RestrictedMock, it aims to allow the developer to declare a narrow interface to the mock that defines what the mocks allows to be called on. The feature of mocks returning mocks by default is extremely useful but not always desired. Quite often you rely on it only at the time you are writing the test but you want it to be disabled at the time the mock is passed into your code. It also prevents user errors when mocking incorrect paths or having typos when calling attributes/methods of the mock. We have tried it internally in our company and it gives quite a nicer user experience for many use cases, specially for new users of mock as it helps out when you mock the wrong path. Posible interfaces: New Mock type, SeledMock which can be used instead of the "common" mock that has an attribute "sealed" which once set to true disables the dynamic generation of "submocks" The final goal is to be able to write tests like: >>> m = mock.Mock() # or = mock.SealableMock() >>> m.method1.return_value.attr1.method2.return_value = 1 >>> mock.seal(m) # or mock.sealed = True >>> m.method1().attr1.method2() # This path has been declared above # 1 >>> m.method1().attr2 # This was not defined so it is going to raise a meaningful exception # Exception: SealedMockAttributeAccess: mock.method1().attr2 |
|||
| msg294969 - (view) | Author: Mario Corchero (mariocj89) * (Python triager) | Date: 2017年06月01日 21:00 | |
Sample implementation using the new class: https://github.com/mariocj89/cpython/commit/2f13963159e239de041cd68273b9fc4a2aa778cd Sample implementation using the new function to seal existing mocks: https://github.com/mariocj89/cpython/commit/9ba039e3996f4bf357d4827123e0b570d84f5bb6 Happy to submit a PR if the idea is accepted. The only benefit I see from the using a separate class is that you will be able to do: >>> m = mock.SealedMock() >>> m.important_attr = 42 >>> m.freeflow_attribute = mock.Mock() >>> mock.seal(m) which will allow to define "subparts of the mock" without the sealing. That said I still prefer the function implementation as it looks much nicer (credit to Victor Stinner for the idea) |
|||
| msg296159 - (view) | Author: Berker Peksag (berker.peksag) * (Python committer) | Date: 2017年06月16日 05:04 | |
I personally never need this feature before so I will add Michael and Robert to nosy list to take their opinions. |
|||
| msg296573 - (view) | Author: Grzegorz Grzywacz (grzgrzgrz3) * | Date: 2017年06月21日 18:45 | |
Existing mock implementation already has that feature. Mock attributes can be limited with `spec` attribute.
>>> inner_m = Mock(spec=["method2"], **{"method2.return_value": 1})
>>> m = Mock(spec=["method1"], **{"method1.return_value": inner_m})
>>>
>>> m.method1().method2()
1
>>>
>>> m.method1().attr
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "/usr/lib/python3.5/unittest/mock.py", line 580, in __getattr__
raise AttributeError("Mock object has no attribute %r" % name)
AttributeError: Mock object has no attribute 'attr'
|
|||
| msg296589 - (view) | Author: Mario Corchero (mariocj89) * (Python triager) | Date: 2017年06月21日 22:15 | |
Whilst I agree that using spec can be used for a similar purpose and I did not know about being able to do nested definitions via the arguments (the **{"method1.return_value": 1}, really cool!) I find the idea of allowing users to halt the mock generation really useful. It is much less disruptive and feels more natural.
Compare:
>>> inner_m = Mock(spec=["method2"], **{"method2.return_value": 1})
>>> m = Mock(spec=["method1"], **{"method1.return_value": inner_m})
with:
>>> m = mock.Mock()
>>> m.method1().method2() = 1
>>> mock.seal(m)
In brief, seal allows users to just add the method to their existing workflow where they use generic mocks. Moreover, it is extremely user friendly, many of the developers that struggle with the mocking module found seal really helpful.
|
|||
| msg296600 - (view) | Author: Michael Foord (michael.foord) * (Python committer) | Date: 2017年06月21日 23:22 | |
I don't see what this buys over spec and autospec. I'd be inclined to close it without a compelling use case beyond what is already supported. |
|||
| msg296609 - (view) | Author: STINNER Victor (vstinner) * (Python committer) | Date: 2017年06月22日 00:09 | |
> I don't see what this buys over spec and autospec. I'd be inclined to close it without a compelling use case beyond what is already supported.
I proposed to Mario to open an issue since I like his API. Even if "sealing" mocks is unlikely to be the most common case, when you need it, I prefer his API over the specs thing which reminds me bad time with mox. I prefer the declarative Python-like API, rather than Mock(spec=["method2"], **{"method2.return_value": 1}).
But yeah, technically specs and sealing seems similar. It's just another way to describe a mock. Since I prefer sealing, I would like to allow users to choose between specs and sealing.
|
|||
| msg296697 - (view) | Author: Michael Foord (michael.foord) * (Python committer) | Date: 2017年06月23日 10:50 | |
Note that you can use an object as the parameter to the spec argument rather than just a list of attributes. Hmmm... I'm not totally opposed to the addition of a "seal_mock" method (optionally with a recurse boolean for child mocks) being added to the Mock/MagicMock classes. It's quite a nice API. I don't like the idea of an additional Mock class for this. |
|||
| msg296705 - (view) | Author: STINNER Victor (vstinner) * (Python committer) | Date: 2017年06月23日 12:34 | |
> I don't like the idea of an additional Mock class for this. Hum, in the current implementation, it's an enhancement of the Mock class, no more a new class. |
|||
| msg301230 - (view) | Author: STINNER Victor (vstinner) * (Python committer) | Date: 2017年09月04日 17:33 | |
I will merge the PR this week, the PR now LGTM. |
|||
| msg304498 - (view) | Author: STINNER Victor (vstinner) * (Python committer) | Date: 2017年10月17日 11:35 | |
New changeset 552be9d7e64f91b8e4ba5b29cd5dcc442d56f92c by Victor Stinner (Mario Corchero) in branch 'master': bpo-30541: Add new method to seal mocks (GH61923) https://github.com/python/cpython/commit/552be9d7e64f91b8e4ba5b29cd5dcc442d56f92c |
|||
| History | |||
|---|---|---|---|
| Date | User | Action | Args |
| 2022年04月11日 14:58:47 | admin | set | github: 74726 |
| 2018年01月05日 17:42:54 | p-ganssle | set | pull_requests: + pull_request4974 |
| 2017年10月17日 11:36:43 | vstinner | set | status: open -> closed resolution: fixed stage: patch review -> resolved |
| 2017年10月17日 11:35:15 | vstinner | set | messages: + msg304498 |
| 2017年09月04日 17:33:16 | vstinner | set | messages: + msg301230 |
| 2017年06月24日 08:05:21 | lkollar | set | nosy:
+ lkollar |
| 2017年06月23日 12:34:02 | vstinner | set | messages: + msg296705 |
| 2017年06月23日 10:50:21 | michael.foord | set | messages: + msg296697 |
| 2017年06月22日 00:09:25 | vstinner | set | messages: + msg296609 |
| 2017年06月21日 23:22:55 | michael.foord | set | messages: + msg296600 |
| 2017年06月21日 22:15:41 | mariocj89 | set | messages: + msg296589 |
| 2017年06月21日 18:45:28 | grzgrzgrz3 | set | nosy:
+ grzgrzgrz3 messages: + msg296573 |
| 2017年06月16日 05:04:36 | berker.peksag | set | nosy:
+ rbcollins, berker.peksag, michael.foord messages: + msg296159 stage: patch review |
| 2017年06月02日 19:49:19 | mariocj89 | set | pull_requests: + pull_request2003 |
| 2017年06月01日 21:49:56 | ericvw | set | nosy:
+ ericvw |
| 2017年06月01日 21:00:59 | mariocj89 | set | messages: + msg294969 |
| 2017年06月01日 20:16:56 | mariocj89 | create | |