unittest unit test mock python unit-testing mocking python-mock

mock - python unittest



Afirmar que una función/método no se llamó utilizando Mock (5)

Estoy usando la biblioteca de Mock para probar mi aplicación, pero quiero afirmar que no se llamó a alguna función. Los documentos mock.assert_called_with hablan de métodos como mock.assert_called_with y mock.assert_called_once_with , pero no encontré nada como mock.assert_not_called o algo relacionado con la verificación de que no se llamó a simulacro.

Podría ir con algo como lo siguiente, aunque no me parece genial ni pitónico:

def test_something: # some actions with patch(''something'') as my_var: try: # args are not important. func should never be called in this test my_var.assert_called_with(some, args) except AssertionError: pass # this error being raised means it''s ok # other stuff

¿Alguna idea de cómo lograr esto?

Gracias por cualquier ayuda :)


A juzgar por otras respuestas, nadie excepto @rob-kennedy habló sobre call_args_list .

Es una herramienta poderosa para que puedas implementar exactamente lo contrario de MagicMock.assert_called_with()

call_args_list es una lista de objetos call . Cada objeto de call representa una llamada realizada en un invocable burlado.

>>> from unittest.mock import MagicMock >>> m = MagicMock() >>> m.call_args_list [] >>> m(42) <MagicMock name=''mock()'' id=''139675158423872''> >>> m.call_args_list [call(42)] >>> m(42, 30) <MagicMock name=''mock()'' id=''139675158423872''> >>> m.call_args_list [call(42), call(42, 30)]

El consumo de un objeto call es fácil, ya que puede compararlo con una tupla de longitud 2, donde el primer componente es una tupla que contiene todos los argumentos posicionales de la llamada relacionada, mientras que el segundo componente es un diccionario de los argumentos clave.

>>> ((42,),) in m.call_args_list True >>> m(42, foo=''bar'') <MagicMock name=''mock()'' id=''139675158423872''> >>> ((42,), {''foo'': ''bar''}) in m.call_args_list True >>> m(foo=''bar'') <MagicMock name=''mock()'' id=''139675158423872''> >>> ((), {''foo'': ''bar''}) in m.call_args_list True

Entonces, una forma de abordar el problema específico del OP es

def test_something(): with patch(''something'') as my_var: assert ((some, args),) not in my_var.call_args_list

Tenga en cuenta que de esta manera, en lugar de simplemente verificar si se ha llamado a un MagicMock.called , a través de MagicMock.called , ahora puede verificar si se ha llamado con un conjunto específico de argumentos.

Eso es útil. Supongamos que desea probar una función que toma una lista y llama a otra función, compute() , para cada uno de los valores de la lista solo si cumplen una condición específica.

Ahora puede simular compute y probar si ha sido invocado con algún valor, pero no con otros.


Aunque es una vieja pregunta, me gustaría añadir que actualmente la biblioteca de mock (backport de unittest.mock) admite el método assert_not_called .

Simplemente actualice el suyo;

pip install mock --upgrade


Cuando prueba utilizando clases hereda unittest.TestCase puede simplemente usar métodos como:

  • assertTrue
  • assertFalse
  • assertEqual

y similar (en la documentación de Python encontrará el resto).

En su ejemplo, podemos simplemente afirmar si la propiedad mock_method.called es False , lo que significa que no se invocó el método.

import unittest from unittest import mock import my_module class A(unittest.TestCase): def setUp(self): self.message = "Method should not be called. Called {times} times!" @mock.patch("my_module.method_to_mock") def test(self, mock_method): my_module.method_to_mock() self.assertFalse(mock_method.called, self.message.format(times=mock_method.call_count))


Esto debería funcionar para su caso;

assert not my_var.called, ''method should not have been called''

Muestra;

>>> mock=Mock() >>> mock.a() <Mock name=''mock.a()'' id=''4349129872''> >>> assert not mock.b.called, ''b was called and should not have been'' >>> assert not mock.a.called, ''a was called and should not have been'' Traceback (most recent call last): File "<stdin>", line 1, in <module> AssertionError: a was called and should not have been


Puede verificar el atributo called , pero si su afirmación falla, lo siguiente que querrá saber es algo acerca de la llamada inesperada, por lo que puede organizar que esa información se muestre desde el principio. Usando unittest , puedes verificar el contenido de call_args_list en call_args_list lugar:

self.assertItemsEqual(my_var.call_args_list, [])

Cuando falla, da un mensaje como este:

AssertionError: Element counts were not equal: First has 0, Second has 1: call(''first argument'', 4)