python / python/cpython

Explain how to properly mock user-defined `__call__`

Abierto
#131,383 9 comentarios 0 reacciones 0 asignados Ver en GitHub

Nadie ha tomado este issue todavía.

docs
Lenguaje dominante
Python
Estrellas
77.2k
Forks
35.9k
Métricas de merge de PR
Métricas de PR pendientes

Descripción

Bug report

Bug description:

Reproduce

from unittest.mock import MagicMock

class A:
    def __init__(self, a):
        ...

    def __call__(self, b, c):
        ...

mocker = MagicMock(spec=A)
mocker(21, 42)
mocker.assert_called_once_with(21, 42)

Current Behavior

TypeError                                 Traceback (most recent call last)
TypeError: too many positional arguments

The above exception was the direct cause of the following exception:

AssertionError                            Traceback (most recent call last)
Cell In[6], line 10
      8 mocker = MagicMock(spec=A)
      9 mocker(21, 42)
---> 10 mocker.assert_called_once_with(21, 42)

File ~/.pyenv/versions/3.12.2/lib/python3.12/unittest/mock.py:956, in NonCallableMock.assert_called_once_with(self, *args, **kwargs)
    951     msg = ("Expected '%s' to be called once. Called %s times.%s"
    952            % (self._mock_name or 'mock',
    953               self.call_count,
    954               self._calls_repr()))
    955     raise AssertionError(msg)
--> 956 return self.assert_called_with(*args, **kwargs)

File ~/.pyenv/versions/3.12.2/lib/python3.12/unittest/mock.py:944, in NonCallableMock.assert_called_with(self, *args, **kwargs)
    942 if actual != expected:
    943     cause = expected if isinstance(expected, Exception) else None
--> 944     raise AssertionError(_error_message()) from cause

AssertionError: expected call not found.
Expected: mock(21, 42)
  Actual: mock(21, 42)

Expected behaviour

It succeeds

Investigation

When passing a class that implements the __call__ method as spec to a mock instance it takes the it takes the signature of the __init__ which if it is the intended behavior is quite confusing.

CPython versions tested on:

3.12, 3.13

Operating systems tested on:

macOS, Linux

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 con el reproductor de MagicMock proporcionado en Python 3.12 o 3.13 y, después, inspecciona unittest/mock.py alrededor de NonCallableMock.assert_called_with y el manejo de firmas relacionado con spec=A. Compara el comportamiento de una clase que define call con el traceback actual. Se considera terminado cuando el comportamiento documentado o implementado hace que la aserción mostrada tenga éxito.

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
Error
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.