Unittest.mock.patch - record result of wrapped function call
Personne n'a encore pris cette issue.
- Langage dominant
- Python
- Étoiles
- 77.2k
- Forks
- 35.9k
- Métriques de merge des PR
- Métriques de PR en attente
Description
Feature or enhancement
Proposal:
I would like to access the return value of a function call wrapped with unittest.mock.patch, that I don't call myself directly.
Motivation
Let's say I have a framework that supports some "before" hooks to allow users to customize some data flowing through the framework.
One could write hook functions for such a framework and publish them.
When doing so, it would make integration tests easier if one could access the return value of a function wrapped with a MagicMock.
# framework.py
def init(before_hook):
... # register the update hook that is later used before doing some action to allow customization of the action
# my_plugin.py
def my_before_hook(some_data: dict) -> dict:
... #do something with some_data eg adding a key
some_data["foo"] = "bar"
return some_data # return the altered data
# test_my_plugin.py
import my_plugin
import framework
def test_my_before_hook():
with unittest.mock.patch("my_plugin.my_before_hook", wraps=my_plugin.my_before_hook) as m:
framework.init(before_hook=m)
... #do something that runs the framework
assert m.called
assert ... # assert m's return value has the key "foo" with the value "bar"
Unfortunately, currently the second assert statement is not really possible - at least I couldn't find anything in the docs, debugger, and LLMs just hallucinated on this one 😅.
Alternatives
There are two alternatives I have considered:
- Digging into the framework and finding a mock target - while this would work, it can be quite tedious, especially when the framework is big
- Wrapping the function in question manually - Definitely possible, but seems to introduce an extra step every time this is necessary and moves the assertion to a an odd place:
# test_my_plugin.py
import my_plugin
import framework
def foo(*args, **kwargs)
result = my_plug.my_before_hook(*args, **kwargs)
assert result["foo"] == "bar" # this only works if the framework doesn't handle AssertionErrors
return result
def test_my_before_hook():
with unittest.mock.patch("my_plugin.my_before_hook", wraps=foo) as m:
framework.init(before_hook=m)
... #do something that runs the framework
assert m.called
Proposed Solution
Record the return value of a "wraps" call and make it available on the call tuple.
I know this could be somewhat problematic due to backwards compatibility, but I'm not entirely sure.
I dove a little bit into the source code and don't think it will be too big of a change both in terms of code and functionality - please correct me if I'm wrong.
I'd be happy to contribute if this is enhancement is desired 🙂
Has this already been discussed elsewhere?
This is a minor feature, which does not need previous discussion elsewhere
Links to previous discussion of this feature:
No response
Guide de contribution
Ouvrir le guide de contribution
Par où commencer
- Lisez l'issue en entier, puis le guide de contribution du projet.
- Signalez en commentaire que vous la prenez — cela évite que deux personnes fassent le même travail.
- Forkez le dépôt et travaillez sur une branche.
- Ouvrez une pull request qui référence le numéro de l'issue.
Piste de recherche
Commencez par lire le comportement existant de unittest.mock.patch, MagicMock, wraps et des tuples d’appels décrit par l’issue, puis examinez l’implémentation et les tests pertinents de unittest.mock. Déterminez comment la valeur de retour d’une fonction enveloppée pourrait être exposée sans casser l’API d’appel actuelle. C’est terminé lorsque le comportement est spécifié, implémenté et couvert par des tests pour les appels enveloppés et la compatibilité.
Rédigé par le modèle d'indexation à partir du texte de l'issue.
Évaluation
- Stack technique
- python
- Domaine
- testing-qa
- Type d'issue
- Fonctionnalité
- Difficulté
- 4/5
- Temps estimé
- 3-5 jours
- Activité
- À l'abandon
- Clarté
- Plutôt claire
- Accessibilité débutants
- 42/100