python / python/cpython

Explain how to properly mock user-defined `__call__`

Aberta
#131,383 9 comentários 0 reações 0 responsáveis Ver no GitHub

Ninguém assumiu esta issue ainda.

docs
Linguagem predominante
Python
Estrelas
77.2k
Forks
36k
Métricas de merge de PRs
Métricas de PR pendentes

Descrição

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

Guia de contribuição

Abrir o guia de contribuição

Primeiros passos

  1. Leia a issue inteira e depois o guia de contribuição do projeto.
  2. Comente na issue dizendo que vai assumir — evita que duas pessoas façam o mesmo trabalho.
  3. Faça um fork do repositório e trabalhe em uma branch.
  4. Abra um pull request que referencie o número da issue.

Direção de pesquisa

Comece com o reprodutor de MagicMock fornecido no Python 3.12 ou 3.13 e, em seguida, inspecione unittest/mock.py em torno de NonCallableMock.assert_called_with e do tratamento de assinatura envolvido em spec=A. Compare o comportamento de uma classe que define call com o traceback atual. Considera-se concluído quando o comportamento documentado ou implementado fizer com que a asserção mostrada seja bem-sucedida.

Escrita pelo modelo de indexação a partir do texto da issue.

Avaliação

Stack de tecnologia
python
Domínio
testing-qa
Tipo de issue
Bug
Dificuldade
4/5
Tempo estimado
3-5 dias
Status de atividade
Estagnada
Clareza
Razoavelmente clara
Facilidade para iniciantes
42/100

Receba novas issues na sua caixa de entrada

Um resumo curto de issues do GitHub para quem está começando.