python / python/cpython

Unittest.mock.patch - record result of wrapped function call

Abierto
#130,368 2 comentarios 0 reacciones 0 asignados Ver en GitHub

Nadie ha tomado este issue todavía.

stdlib type-feature
Lenguaje dominante
Python
Estrellas
77.2k
Forks
36k
Métricas de merge de PR
Métricas de PR pendientes

Descripción

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:

  1. Digging into the framework and finding a mock target - while this would work, it can be quite tedious, especially when the framework is big
  2. 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

Guía de contribución

Abrir la guía de contribución

Primeros pasos

  1. Lee el issue completo y luego la guía de contribución del proyecto.
  2. Comenta en el issue que vas a ocuparte — evita que dos personas hagan lo mismo.
  3. Haz un fork del repositorio y trabaja en una rama.
  4. Abre un pull request que haga referencia al número del issue.

Línea de trabajo

Comienza leyendo el comportamiento existente de unittest.mock.patch, MagicMock, wraps y las tuplas de llamadas descrito por el issue, y después inspecciona la implementación y las pruebas relevantes de unittest.mock. Determina cómo podría exponerse el valor de retorno de una función envuelta sin romper la API de llamadas actual. Se considera terminado cuando el comportamiento está especificado, implementado y cubierto por pruebas para llamadas envueltas y compatibilidad.

Escrito por el modelo de indexación a partir del texto del issue.

Evaluación

Stack tecnológico
python
Área
testing-qa
Tipo de issue
Nueva funcionalidad
Dificultad
4/5
Tiempo estimado
3-5 días
Estado de actividad
Estancado
Claridad
Bastante claro
Aptitud para principiantes
42/100

Recibe los nuevos issues en tu correo

Un resumen breve de issues de GitHub para principiantes.