2012-08-29 17 views
84

estoy usando la biblioteca Mock para probar mi aplicación, pero quiero afirmar que alguna función no fue llamado. docs simulacros hablan de métodos como mock.assert_called_with y mock.assert_called_once_with, pero no encontré nada parecido mock.assert_not_called o algo relacionado para verificar simulacro fue NO llamada.afirmar una función/método no fue llamada usando Mock

Podría seguir con algo como lo siguiente, aunque no parece fría ni Pythonic:

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 :)

+0

Como señala en su respuesta @Ahmet, assert_not_called ahora es compatible, también en el backport (https://docs.python.org/3/library/unittest.mock.html#unittest.mock .Mock.assert_not_llamado). – Martin

Respuesta

106

Esto debería funcionar para su caso;

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

Ejemplo;

>>> 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 
+0

¿Requiere esta respuesta Django? Me aparece un error: 'AttributeError: instancia de MockCallable no tiene atributo 'called'' –

+0

@NathanArthur Hm, no lo creo, después de' sudo easy_install -U mock' y 'de simulacro de importación Mock' en MacOS, el arriba funciona sin problemas. Nunca instalado Django :) –

+0

Hmm. Eso es extraño. Estoy ejecutando Python 2.7.1 y estoy usando unittest y 'from mock import Mock' con Python Mock 0.1.0 para mis pruebas. ¿Algo de eso suena problemático? –

25

puede comprobar el atributo called, pero si falla su afirmación, la siguiente cosa que usted querrá saber es algo sobre la llamada inesperada, por lo que es posible que así los arreglos para que la información que se mostrará desde el comienzo. Usando unittest, se puede comprobar el contenido de call_args_list lugar:

self.assertItemsEqual(my_var.call_args_list, []) 

Cuando falla, se da un mensaje como este:

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

Cuando se prueba utilizando clase hereda unittest.TestCase puede sólo tiene que utilizar métodos como:

  • assertTrue
  • assertFalse
  • assertEqual

y similares (en python documentation a encontrar el resto).

En su ejemplo podemos simplemente afirmar si mock_method.called propiedad es Falso, lo que significa que el método no fue llamado.

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)) 
0

A juzgar por otras respuestas, nadie excepto @rob-kennedy hablado de la call_args_list.

Es una poderosa herramienta para la que se puede implementar el contrario exacto de MagicMock.assert_called_with()

call_args_list es una lista de objetos call. Cada objeto call representa una llamada realizada en un exigible 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 se puede comparar 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 la palabra clave argumentos.

>>> ((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 

Por lo tanto, una forma de abordar el problema específico de la 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 comprobar si un ser burlado exigible ha sido llamado, a través de MagicMock.called, ahora se puede compruebe si ha sido 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 satisfacen una condición específica.

Ahora puede simular compute, y probar si se ha llamado a algún valor pero no a otros.

26

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

Simplemente actualice el suyo;

pip install mock --upgrade

Cuestiones relacionadas