-
-
Notifications
You must be signed in to change notification settings - Fork 29.9k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add restricted mocks to the python unittest mocking framework #74726
Comments
Define a way to disable the automatic generation of submocks when accessing an attribute of a mock which is not set. Rationale: It also prevents user errors when mocking incorrect paths or having typos when calling attributes/methods of the mock. Posible interfaces: The final goal is to be able to write tests like:
>>> 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 |
Sample implementation using the new class: Sample implementation using the new function to seal existing mocks: 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:
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) |
I personally never need this feature before so I will add Michael and Robert to nosy list to take their opinions. |
Existing mock implementation already has that feature. Mock attributes can be limited with >>> 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' |
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. |
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. |
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. |
Hum, in the current implementation, it's an enhancement of the Mock class, no more a new class. |
I will merge the PR this week, the PR now LGTM. |
Note: these values reflect the state of the issue at the time it was migrated and might not reflect the current state.
Show more details
GitHub fields:
bugs.python.org fields:
The text was updated successfully, but these errors were encountered: