Cuando se usa unittest.mock.patch, ¿por qué autospec no es True de forma predeterminada?

Cuando parchea una función usando simulacro, tiene la opción de especificar autospec como Verdadero:

Si establece autospec = Verdadero, la simulación se creará con una especificación del objeto que se está reemplazando. Todos los atributos del simulacro también tendrán la especificación del atributo correspondiente del objeto que se reemplaza. Los métodos y funciones que se están burlando tendrán sus argumentos verificados y generarán un error de tipo si se les llama con la firma incorrecta.

( http://www.voidspace.org.uk/python/mock/patch.html )

Me pregunto por qué este no es el comportamiento por defecto? ¿Seguramente casi siempre querremos detectar el paso de parámetros incorrectos a cualquier función que parchemos?

La única forma clara de explicar esto, es en realidad citar la documentación sobre el inconveniente de utilizar la especulación automática y por qué debe tener cuidado al usarla:

Sin embargo, esto no está exento de advertencias y limitaciones, por lo que no es el comportamiento predeterminado. Para saber qué atributos están disponibles en el objeto de especificación, autospec debe realizar una introspección (atributos de acceso) de la especificación. A medida que recorre los atributos en el simulacro, un recorrido correspondiente del objeto original está ocurriendo bajo el capó. Si alguno de sus objetos especificados tiene propiedades o descriptores que pueden desencadenar la ejecución del código, es posible que no pueda usar Autospec. Por otro lado, es mucho mejor diseñar sus objetos para que la introspección sea segura [4].

Un problema más serio es que es común que los atributos de instancia se creen en el método init y no existan en la clase. autospec no puede conocer los atributos creados dinámicamente y restringe la API a los atributos visibles.

Creo que la clave para llevar aquí es tener en cuenta esta línea: autospec no puede conocer los atributos creados dinámicamente y restringe la API a los atributos visibles.

Entonces, para ayudar a ser más explícito con un ejemplo de dónde se rompe la exploración automática, este ejemplo tomado de la documentación muestra esto:

>>> class Something: ... def __init__(self): ... self.a = 33 ... >>> with patch('__main__.Something', autospec=True): ... thing = Something() ... thing.a ... Traceback (most recent call last): ... AttributeError: Mock object has no attribute 'a' 

Como puede ver, la especificación automática no tiene idea de que se está creando un atributo al crear su objeto Something .

Por lo general, para mí, me burlo de los parches y no uso mucho autospec, ya que el comportamiento suele estar en línea con mis expectativas.

No hay nada de malo en asignar un valor a su atributo de instancia.

Observe el siguiente ejemplo funcional:

 import unittest from mock import patch def some_external_thing(): pass def something(x): return x class MyRealClass: def __init__(self): self.a = some_external_thing() def test_thing(self): return something(self.a) class MyTest(unittest.TestCase): def setUp(self): self.my_obj = MyRealClass() @patch('__main__.some_external_thing') @patch('__main__.something') def test_my_things(self, mock_something, mock_some_external_thing): mock_some_external_thing.return_value = "there be dragons" self.my_obj.a = mock_some_external_thing.return_value self.my_obj.test_thing() mock_something.assert_called_once_with("there be dragons") if __name__ == '__main__': unittest.main() 

Entonces, solo digo que para mi caso de prueba quiero asegurarme de que el método some_external_thing() no afecte el comportamiento de mi prueba de some_external_thing() , así que solo le estoy asignando el atributo de instancia a mock_some_external_thing.return_value = "there be dragons" .