2011-11-18 15 views
78

Estoy usando mock con Python y me preguntaba cuál de esos dos enfoques es mejor (léase: más pitónico).Burlarse de una clase: Mock() o parche()?

Método uno: Solo crea un objeto falso y úsalo. El código es el siguiente:

def test_one (self): 
    mock = Mock() 
    mock.method.return_value = True 
    self.sut.something(mock) # This should called mock.method and checks the result. 
    self.assertTrue(mock.method.called) 

Método dos: El uso de parches para crear una maqueta. El código es el siguiente:

@patch("MyClass") 
def test_two (self, mock): 
    instance = mock.return_value 
    instance.method.return_value = True 
    self.sut.something(instance) # This should called mock.method and checks the result. 
    self.assertTrue(instance.method.called) 

Ambos métodos hacen lo mismo. No estoy seguro de las diferencias.

¿Alguien podría aclararme?

+9

Como una persona que nunca han probado ninguno Mock() o parche, siento que la primera versión es más clara y muestra lo que quiere hacer, a pesar de que no tengo ningún conocimiento de la diferencia real No sé si esto es de alguna ayuda o no, pero pensé que podría ser útil transmitir lo que un programador no iniciado podría sentir. –

+1

@MichaelBrennan: Gracias por tu comentario. Es útil de hecho. – Sardathrion

Respuesta

107

mock.patch es una criatura muy diferente de mock.Mock. patchreemplaza la clase con un objeto simulado y te permite trabajar con la instancia simulada. Echar un vistazo a este fragmento:

>>> class MyClass(object): 
... def __init__(self): 
...  print 'Created [email protected]{0}'.format(id(self)) 
... 
>>> def create_instance(): 
... return MyClass() 
... 
>>> x = create_instance() 
Created [email protected] 
>>> 
>>> @mock.patch('__main__.MyClass') 
... def create_instance2(MyClass): 
... MyClass.return_value = 'foo' 
... return create_instance() 
... 
>>> i = create_instance2() 
>>> i 
'foo' 
>>> def create_instance(): 
... print MyClass 
... return MyClass() 
... 
>>> create_instance2() 
<mock.Mock object at 0x100505d90> 
'foo' 
>>> create_instance() 
<class '__main__.MyClass'> 
Created [email protected] 
<__main__.MyClass object at 0x100505d90> 

patch reemplaza MyClass de una manera que le permite controlar el uso de la clase de funciones que realice la llamada. Una vez que parchee una clase, las referencias a la clase se reemplazan por completo por la instancia simulada.

mock.patch se usa generalmente cuando prueba algo que crea una nueva instancia de una clase dentro de la prueba. mock.Mock las instancias son más claras y preferidas. Si su método self.sut.something creó una instancia de MyClass en lugar de recibir una instancia como parámetro, entonces mock.patch sería apropiado aquí.

+2

@ D.Shawley, ¿cómo hacemos un parche a una clase instanciada dentro de otra clase que debe estar bajo prueba? – ravi404

+4

@ravz: indique [leer ". Esta es una de las cosas más difíciles de conseguir para que funcione correctamente. –

+0

Mi prueba simulada es similar a ** Método dos **. Quiero que la instancia de MyClass genere una excepción. He intentado ambos, mock.side_effect y mock.return_value.side_effect y esos no funcionaron. ¿Qué debo hacer? – Hussain

4

Tengo un YouTube video en esto.

Respuesta corta: Usa mock cuando pases en lo que quieras burlado, y patch si no lo eres. De los dos, el simulacro es muy preferido porque significa que estás escribiendo código con una inyección de dependencia adecuada.

ejemplo tonto:

# Use a mock to test this. 
my_custom_tweeter(twitter_api, sentence): 
    sentence.replace('cks','x') # We're cool and hip. 
    twitter_api.send(sentence) 

# Use a patch to mock out twitter_api. You have to patch the Twitter() module/class 
# and have it return a mock. Much uglier, but sometimes necessary. 
my_badly_written_tweeter(sentence): 
    twitter_api = Twitter(user="XXX", password="YYY") 
    sentence.replace('cks','x') 
    twitter_api.send(sentence) 
Cuestiones relacionadas