Categorías
Python

Pandas tramas de datos 101

 

Tabla de Contenidos

  • Lo que se burla?
  • El pitón Mock Biblioteca
  • El Mock ObjectLazy Atributos y MethodsAssertions y InspectionManaging una de Mock Volver ValueManaging lateral de una maqueta EffectsConfiguring Su Mock
  • Lazy atributos y métodos
  • Las afirmaciones e inspección
  • La gestión de un simulacro de valor devuelto
  • Gestión lateral de una maqueta efectos
  • Configuración del parche Mock
  • () parche () como un Decoratorpatch () como un Contexto ManagerPatching AttributesWhere de un objeto al parche Patch
  • () como un parche decorador
  • () como un Contexto Gestor
  • aplicar un parche de objetos atributos
  • Dónde Patch
  • comunes ProblemsChanges Burlándose a Objeto Interfaces y MisspellingsChanges a las dependencias
  • cambios externos a Objeto Interfaces y faltas de ortografía
  • cambios a External dependencias
  • evitar problemas más comunes gracias Especificaciones
  • Conclusión

T G_7

  • Lazy atributos y métodos
  • Las afirmaciones e inspección
  • La gestión de un simulacro de valor devuelto
  • La gestión de un simulacro de efectos secundarios
  • Configuración del parche Mock
    • () como un parche decorador
    • () como un Contexto Gestor
    • Parches de un objeto Atributos
    • Dónde Patch
    • cambios a objetos Interfaces y faltas de ortografía
    • cambios a External dependencias

    Cuando se está escribiendo código robusto, las pruebas son esenciales para la verificación de que su lógica de la aplicación es correcta, fiable y eficiente. Sin embargo, el valor de las pruebas depende de lo bien que demuestran estos criterios. Obstáculos tales como la lógica compleja y dependencias impredecibles hacen que escribir pruebas valiosas difícil. La biblioteca de objetos simulacro de Python, unittest.mock, puede ayudar a superar estos obstáculos.

    Al final de este artículo, usted será capaz de:

    • Crear Python objetos simulados utilizando Mock
    • Afirmar que está utilizando objetos como se pretendía
    • Inspeccionar los datos de uso almacenados en su Python burla
    • Configurar ciertos aspectos de su maqueta de objetos de Python
    • sustituya su burla para los objetos reales utilizando parche () Evitar problemas
    • comunes inherentes en Python burlarse

    Vamos a empezar por ver lo que es de burla y cómo va a mejorar sus ensayos. Bono

    gratuito: 5 pensamientos sobre Python Maestría, un curso gratuito para los desarrolladores de Python que muestra la hoja de ruta y la mentalidad que necesita para tomar sus habilidades de Python al siguiente nivel.

    Lo que se burla?

    un objeto simulacro de sustitutos e imita un objeto real dentro de un entorno de prueba. Es una herramienta versátil y poderosa para mejorar la calidad de las pruebas.

    Una de las razones para utilizar Python objetos simulados es controlar el comportamiento de su código durante la prueba.

    Por ejemplo, si su código hace peticiones HTTP a servicios externos, a continuación, ejecutar sus pruebas previsiblemente sólo en tanto que los servicios se están comportando como se esperaba. A veces, un cambio temporal en el comportamiento de estos servicios externos puede causar fallos intermitentes dentro de su serie de pruebas.

    Debido a esto, sería mejor para poner a prueba su código en un entorno controlado. Sustitución de la solicitud real con un objeto de burla le permitirá simular interrupciones de servicios externos y las respuestas exitosas de una manera predecible.

    A veces, es difícil de probar ciertas áreas de su código base. Tales áreas incluyen excepto bloques y si las declaraciones que son difíciles de satisfacer. El uso de objetos simulados Python puede ayudar a controlar la ruta de ejecución de su código para llegar a esas zonas y mejorar su cobertura de código.

    Otra razón para utilizar los objetos de imitación es entender mejor cómo se está usando sus homólogos reales en el código. Una pitón objeto de burla contiene datos sobre su uso que puede inspeccionar tales como:

    • Si llamó un método
    • Cómo llamó al método
    • ¿Con qué frecuencia se llamó al método

    La comprensión de lo que hace un objeto de burla es el primer paso para aprender a usar una.

    Ahora, verá cómo utilizar Python objetos simulados. librería de objetos mock

    El pitón Mock Biblioteca

    El Python es unittest.mock. Se proporciona una manera fácil de introducir burla en sus pruebas.

    Nota: La biblioteca estándar incluye unittest.mock en Python 3.3 y posteriores. Si está utilizando una versión anterior de Python, tendrá que instalar el backport oficial de la biblioteca. Para ello, instale simulacro de PyPI:

    $ pip install mock

    unittest.mock proporciona una clase llamada simulados que se va a utilizar para imitar a los objetos reales en su código base. ofertas simuladas increíble flexibilidad y datos interesantes. Esto, junto con sus subclases, se reunirá la mayoría de las necesidades de Python burlones que se enfrentará en sus pruebas.

    La biblioteca también proporciona una función, llamada parche (), que sustituye a los objetos reales en el código con casos Mock. Puede usar el parche () ya sea como un decorador o un gestor de contexto, que le permite controlar el alcance en el cual puede ser burlado el objeto. Una vez que las salidas de alcance designados, parche () va a limpiar su código mediante la sustitución de los objetos imitó con sus contrapartes originales.

    Por último, unittest.mock proporciona soluciones para algunos de los problemas inherentes a burlarse de los objetos.

    Ahora, usted tiene una mejor comprensión de lo que es burla y la biblioteca que va a utilizar para hacerlo. buceo de entrar y explorar qué características y funcionalidades unittest.mock ofertas.

    El Mock objeto

    ofertas unittest.mock una clase base para burlarse de objetos llamados Mock. Los casos de uso para Mock son prácticamente ilimitadas, ya Mock es tan flexible.

    Comience por crear una nueva instancia Mock:

    >>> from unittest.mock import Mock
    >>> mock = Mock()
    >>> mock

    Ahora, usted es capaz de sustituir un objeto en el código con su nuevo Mock. Puede hacer esto pasando como argumento a una función o mediante la redefinición de otro objeto:

    # Pass mock as an argument to do_something()
    do_something(mock)

    # Patch the json library
    json = mock

    Al sustituir un objeto en su código, la maqueta debe parecerse al objeto real que está reemplazando. De lo contrario, su código no será capaz de utilizar el Mock en lugar del objeto original.

    Por ejemplo, si usted está burlando de la biblioteca JSON y su programa llama a vertederos (), entonces su objeto de burla Python también debe contener vertederos ().

    A continuación, veremos cómo Mock se ocupa de este problema.

    Lazy atributos y métodos

    una maqueta debe simular cualquier objeto al que reemplaza. Para lograr esta flexibilidad, se crea sus atributos cuando se accede a ellos:

    >>> mock.some_attribute

    >>> mock.do_something()

    Desde Mock puede crear atributos arbitrarios sobre la marcha, es adecuado para sustituir cualquier objeto.

    Mediante un ejemplo de antes, si estás burlando de la biblioteca JSON y le llamaremos vertederos (), el objeto de burla Python creará el método de modo que su interfaz puede coincidir con la interfaz de la biblioteca:

    >>> json = Mock()
    >>> json.dumps()

    Aviso dos características clave de este versión burlado de los vertederos ():

    a diferencia de los vertederos de reales (), este método requiere burlado sin argumentos. De hecho, se aceptará cualquier argumento que se pasa a ella.

    El valor de retorno de los vertederos () es también un simulacro. La capacidad de Mock para definir recursivamente otros burla permite para su uso en situaciones complejas burla:

    >>> json = Mock()
    >>> json.loads('{"k": "v"}').get('k')

    Debido a que el valor de retorno de cada método burlado es también un Mock, usted puede utilizar su burla en una multitud de formas.

    Mocks son flexibles, pero también son informativos. A continuación, usted aprenderá cómo se pueden utilizar los simulacros de entender su código mejor.

    casos

    afirmaciones e Inspección

    Mock almacenar datos en la forma que los utilizó. Por ejemplo, se puede ver si se llama a un método, cómo se llama el método, y así sucesivamente. Hay dos formas principales de usar esta información.

    En primer lugar, se puede afirmar que su programa utiliza un objeto como se esperaba:

    >>> from unittest.mock import Mock

    >>> # Create a mock object
    ... json = Mock()

    >>> json.loads('{"key": "value"}')

    >>> # You know that you called loads() so you can
    >>> # make assertions to test that expectation
    ... json.loads.assert_called()
    >>> json.loads.assert_called_once()
    >>> json.loads.assert_called_with('{"key": "value"}')
    >>> json.loads.assert_called_once_with('{"key": "value"}')

    >>> json.loads('{"key": "value"}')

    >>> # If an assertion fails, the mock will raise an AssertionError
    ... json.loads.assert_called_once()
    Traceback (most recent call last):
    File "", line 1, in
    File "/usr/local/Cellar/python/3.6.5/Frameworks/Python.framework/Versions/3.6/lib/python3.6/unittest/mock.py", line 795, in assert_called_once
    raise AssertionError(msg)
    AssertionError: Expected 'loads' to have been called once. Called 2 times.

    >>> json.loads.assert_called_once_with('{"key": "value"}')
    Traceback (most recent call last):
    File "", line 1, in
    File "/usr/local/Cellar/python/3.6.5/Frameworks/Python.framework/Versions/3.6/lib/python3.6/unittest/mock.py", line 824, in assert_called_once_with
    raise AssertionError(msg)
    AssertionError: Expected 'loads' to be called once. Called 2 times.

    >>> json.loads.assert_not_called()
    Traceback (most recent call last):
    File "", line 1, in
    File "/usr/local/Cellar/python/3.6.5/Frameworks/Python.framework/Versions/3.6/lib/python3.6/unittest/mock.py", line 777, in assert_not_called
    raise AssertionError(msg)
    AssertionError: Expected 'loads' to not have been called. Called 2 times.

    .assert_called () asegura que llamó al método burlado mientras .assert_called_once () comprueba que llamó al método exactamente una vez.

    funciones Ambas variantes tienen afirmación que le permiten inspeccionar los argumentos que se pasan al método burlado:

    • .assert_called_with (* args, ** kwargs)
    • .assert_called_once_with (* args, ** kwargs)

    Para pasar estos afirmaciones, debe llamar al método burlado con los mismos argumentos que se pasa al método real:

    >>> json = Mock()
    >>> json.loads(s='{"key": "value"}')
    >>> json.loads.assert_called_with('{"key": "value"}')
    Traceback (most recent call last):
    File "", line 1, in
    File "/usr/local/Cellar/python/3.6.5/Frameworks/Python.framework/Versions/3.6/lib/python3.6/unittest/mock.py", line 814, in assert_called_with
    raise AssertionError(_error_message()) from cause
    AssertionError: Expected call: loads('{"key": "value"}')
    Actual call: loads(s='{"key": "value"}')
    >>> json.loads.assert_called_with(s='{"key": "value"}')

    json.loads.assert_called_with ( ‘{ ‘clave’: ‘valor’}’) levantó una AssertionError, ya que le espera a la llamada (cargas) con un argumento posicional, pero en realidad se llama con un argumento de palabra clave. json.loads.assert_called_with (s = ‘{ «clave»: «valor»}’) se pone esta afirmación correcta.

    segundo lugar, usted puede ver los atributos especiales para entender cómo su aplicación utiliza un objeto:

    >>> from unittest.mock import Mock

    >>> # Create a mock object
    ... json = Mock()
    >>> json.loads('{"key": "value"}')

    >>> # Number of times you called loads():
    ... json.loads.call_count
    1
    >>> # The last loads() call:
    ... json.loads.call_args
    call('{"key": "value"}')
    >>> # List of loads() calls:
    ... json.loads.call_args_list
    [call('{"key": "value"}')]
    >>> # List of calls to json's methods (recursively):
    ... json.method_calls
    [call.loads('{"key": "value"}')]

    Usted puede escribir pruebas que utilizan estos atributos para asegurarse de que sus objetos se comportan como se pretendía.

    Ahora, puede crear burla e inspeccionar sus datos de uso. A continuación, verá cómo personalizar los métodos burlado de modo que sean más útiles en el entorno de prueba.

    La gestión de una de Mock y valor devuelto

    Una razón para utilizar burla es controlar el comportamiento de su código durante las pruebas. Una forma de hacer esto es especificar el valor devuelto por una función. Usemos un ejemplo para ver cómo funciona esto.

    En primer lugar, crear un archivo llamado my_calendar.py. Añadir is_weekday (), una función de fecha y hora que utiliza la biblioteca de Python para determinar si es o no hoy es un día de la semana. Por último, escribir una prueba que afirma que la función funciona como se esperaba:

    from datetime import datetime

    def is_weekday():
    today = datetime.today()
    # Python's datetime library treats Monday as 0 and Sunday as 6
    return (0 <= today.weekday() < 5) # Test if today is a weekday assert is_weekday()

    Desde que está probando si hoy es un día laborable, el resultado depende del día se ejecuta la prueba:

    $ python my_calendar.py

    Si este comando no produce ninguna salida, la afirmación se ha realizado correctamente. Por desgracia, si ejecuta el comando en un fin de semana, obtendrá un AssertionError:

    $ python my_calendar.py
    Traceback (most recent call last):
    File "test.py", line 9, in
    assert is_weekday()
    AssertionError

    Al escribir pruebas, es importante asegurarse de que los resultados son predecibles. Puede usar Mock para eliminar la incertidumbre de su código durante la prueba. En este caso, puede burlarse de fecha y hora y establecer el .return_value para .HOY () para un día que le conviene más:

    import datetime
    from unittest.mock import Mock

    # Save a couple of test days
    tuesday = datetime.datetime(year=2019, month=1, day=1)
    saturday = datetime.datetime(year=2019, month=1, day=5)

    # Mock datetime to control today's date
    datetime = Mock()

    def is_weekday():
    today = datetime.datetime.today()
    # Python's datetime library treats Monday as 0 and Sunday as 6
    return (0 <= today.weekday() < 5) # Mock .today() to return Tuesday datetime.datetime.today.return_value = tuesday # Test Tuesday is a weekday assert is_weekday() # Mock .today() to return Saturday datetime.datetime.today.return_value = saturday # Test Saturday is not a weekday assert not is_weekday()

    En el ejemplo, .HOY () es un método burlado. Que haya eliminado la incompatibilidad mediante la asignación de un día específico para .return_value de la maqueta. De esta manera, cuando se llama .HOY (), que devuelve la fecha y hora que especificó.

    En la primera prueba, se asegura el martes es un día laborable. En la segunda prueba, verificar que el sábado no es un día laborable. Ahora, no importa qué día se ejecuta sus pruebas de porque se ha burlado de fecha y hora y tener control sobre el comportamiento del objeto.

    Lectura adicional: Aunque burlarse de fecha y hora como esto es un ejemplo de buenas prácticas para el uso de Mock, una biblioteca fantástica ya existe por burlarse de fecha y hora llamada freezegun.

    Cuando la construcción de sus pruebas, es probable que se encontrará con casos en los que burlaban valor de retorno de una función no será suficiente. Esto se debe a que las funciones son a menudo más complicado que un simple flujo unidireccional de la lógica.

    A veces, tendrá que hacer funciones devuelven valores diferentes cuando se les llama más de una vez o incluso excepciones aumento. Esto se puede hacer usando .side_effect.

    La gestión de un simulacro de efectos secundarios

    Se puede controlar el comportamiento de su código mediante la especificación de los efectos secundarios de una función burlado. A define .side_effect lo que sucede cuando se llama a la función burlado.

    para probar cómo funciona este, añadir una nueva función a my_calendar.py: get_holidays

    import requests

    def get_holidays():
    r = requests.get('http://localhost/api/holidays')
    if r.status_code == 200:
    return r.json()
    return None

    () hace una petición al servidor localhost para un conjunto de días festivos. Si el servidor responde con éxito, get_holidays () devuelve un diccionario. De lo contrario, el método devolverá None.

    Puede probar cómo get_holidays () responderán a un tiempo de espera de conexión mediante el establecimiento de requests.get.side_effect.

    Para este ejemplo, sólo se verá el código relevante de my_calendar.py. Usted va a construir un caso de prueba usando la biblioteca de Python unittest: .assertRaises uso

    import unittest
    from requests.exceptions import Timeout
    from unittest.mock import Mock

    # Mock requests to control its behavior
    requests = Mock()

    def get_holidays():
    r = requests.get('http://localhost/api/holidays')
    if r.status_code == 200:
    return r.json()
    return None

    class TestCalendar(unittest.TestCase):
    def test_get_holidays_timeout(self):
    # Test a connection timeout
    requests.get.side_effect = Timeout
    with self.assertRaises(Timeout):
    get_holidays()

    if __name__ == '__main__':
    unittest.main()

    usted () para verificar que los get_holidays () lanza una excepción dado el nuevo efecto secundario de get ().

    ejecutar esta prueba para ver el resultado de su prueba:

    $ python my_calendar.py
    .
    -------------------------------------------------------
    Ran 1 test in 0.000s

    OK

    Si quieres ser un poco más dinámico, se puede establecer .side_effect a una función que Mock invocará cuando se llama a su método de burla. Las acciones simuladas el valor argumentos y retorno de la función .side_effect:

    import requests
    import unittest
    from unittest.mock import Mock

    # Mock requests to control its behavior
    requests = Mock()

    def get_holidays():
    r = requests.get('http://localhost/api/holidays')
    if r.status_code == 200:
    return r.json()
    return None

    class TestCalendar(unittest.TestCase):
    def log_request(self, url):
    # Log a fake request for test output purposes
    print(f'Making a request to {url}.')
    print('Request received!')

    # Create a new Mock to imitate a Response
    response_mock = Mock()
    response_mock.status_code = 200
    response_mock.json.return_value = {
    '12/25': 'Christmas',
    '7/4': 'Independence Day',
    }
    return response_mock

    def test_get_holidays_logging(self):
    # Test a successful, logged request
    requests.get.side_effect = self.log_request
    assert get_holidays()['12/25'] == 'Christmas'

    if __name__ == '__main__':
    unittest.main()

    En primer lugar, se creó .log_request (), que toma una dirección URL, registra determinada impresión de salida utilizando (), a continuación, devuelve una respuesta falsa. A continuación, se ajusta el .side_effect de get () para .log_request (), que va a utilizar cuando se llama get_holidays (). Cuando se ejecuta la prueba, verá que get () hacia delante sus argumentos a .log_request () acepta entonces el valor de retorno y la devuelve así:

    $ python my_calendar.py
    Making a request to http://localhost/api/holidays.
    Request received!
    .
    -------------------------------------------------------
    Ran 1 test in 0.000s

    OK

    Gran! Las declaraciones de impresión () registra los valores correctos. Además, get_holidays () devuelven el diccionario de las vacaciones.

    .side_effect también puede ser un iterable. El iterable debe consistir en valores de retorno, excepciones, o una mezcla de ambos. El iterables producirá su siguiente valor cada vez que se llama a su método de burla. Por ejemplo, se puede probar que un reintento después de un tiempo de espera devuelve una respuesta exitosa:

    import unittest
    from requests.exceptions import Timeout
    from unittest.mock import Mock

    # Mock requests to control its behavior
    requests = Mock()

    def get_holidays():
    r = requests.get('http://localhost/api/holidays')
    if r.status_code == 200:
    return r.json()
    return None

    class TestCalendar(unittest.TestCase):
    def test_get_holidays_retry(self):
    # Create a new Mock to imitate a Response
    response_mock = Mock()
    response_mock.status_code = 200
    response_mock.json.return_value = {
    '12/25': 'Christmas',
    '7/4': 'Independence Day',
    }
    # Set the side effect of .get()
    requests.get.side_effect = [Timeout, response_mock]
    # Test that the first request raises a Timeout
    with self.assertRaises(Timeout):
    get_holidays()
    # Now retry, expecting a successful response
    assert get_holidays()['12/25'] == 'Christmas'
    # Finally, assert .get() was called twice
    assert requests.get.call_count == 2

    if __name__ == '__main__':
    unittest.main()

    La primera vez que llame get_holidays (), get () plantea un tiempo de espera. La segunda vez, el método devuelve un diccionario vacaciones válidos. Estos efectos secundarios coinciden con el orden en que aparecen en la lista aprobada a .side_effect.

    Puede establecer .return_value y .side_effect en un simulacro de forma directa. Sin embargo, debido a que un objeto de burla Python tiene que ser flexible en la creación de sus atributos, hay una mejor manera de configurar estos y otros ajustes.

    la configuración de su Mock

    Se puede configurar un simulacro de configurar algunos de los comportamientos del objeto. Algunos miembros configurables incluyen .side_effect, .return_value, y .name. Configura un Mock cuando se crea uno o cuando se utiliza .configure_mock ().

    Se puede configurar un Mock especificando ciertos atributos al inicializar un objeto:

    >>> mock = Mock(side_effect=Exception)
    >>> mock()
    Traceback (most recent call last):
    File "", line 1, in
    File "/usr/local/Cellar/python/3.6.5/Frameworks/Python.framework/Versions/3.6/lib/python3.6/unittest/mock.py", line 939, in __call__
    return _mock_self._mock_call(*args, **kwargs)
    File "/usr/local/Cellar/python/3.6.5/Frameworks/Python.framework/Versions/3.6/lib/python3.6/unittest/mock.py", line 995, in _mock_call
    raise effect
    Exception

    >>> mock = Mock(name='Real Python Mock')
    >>> mock

    >>> mock = Mock(return_value=True)
    >>> mock()
    True

    Mientras .side_effect y .return_value se pueden establecer en la instancia Mock, en sí, otros atributos como .name sólo se puede establecer a través .__ init __ () o .configure_mock (). Si se intenta establecer la .name del Mock en la instancia, se obtiene un resultado diferente:

    >>> mock = Mock(name='Real Python Mock')
    >>> mock.name

    >>> mock = Mock()
    >>> mock.name = 'Real Python Mock'
    >>> mock.name
    'Real Python Mock'

    .name es un atributo común para los objetos a su uso. Así, Mock no le permite establecer dicho valor en la instancia de la misma manera que con .return_value o .side_effect. Si accede a mock.name va a crear un atributo .name en lugar de la configuración de su maqueta.

    Puede configurar un simulacro usando .configure_mock existente ():

    >>> mock = Mock()
    >>> mock.configure_mock(return_value=True)
    >>> mock()
    True

    Por desempaquetar un diccionario en cualquiera .configure_mock () o Mock .__ init __ (), incluso se puede configurar atributos de su maqueta de Python de objetos. El uso de configuraciones Mock, podría simplificar un ejemplo anterior:

    # Verbose, old Mock
    response_mock = Mock()
    response_mock.json.return_value = {
    '12/25': 'Christmas',
    '7/4': 'Independence Day',
    }

    # Shiny, new .configure_mock()
    holidays = {'12/25': 'Christmas', '7/4': 'Independence Day'}
    response_mock = Mock(**{'json.return_value': holidays})

    Ahora, puede crear y configurar Python objetos simulados. También puede utilizar burla para controlar el comportamiento de su aplicación. Hasta ahora, usted ha utilizado burla como argumentos a las funciones u objetos de parches en el mismo módulo que sus pruebas.

    A continuación, usted aprenderá cómo sustituir sus burla para los objetos reales en otros módulos. parche

    ()

    unittest.mock proporciona un poderoso mecanismo para objetos de burla, llamada parche (), que busca un objeto en un determinado módulo y sustituye al objeto con una maqueta.

    Por lo general, se utiliza el parche () como un decorador o un gestor de contexto para proporcionar un ámbito en el que va a burlarse del objeto de destino.

    parche

    () como un decorador

    Si quiere burlarse de un objeto para la duración de su función de prueba de todo, se puede usar el parche () como decorador función.

    Para ver cómo funciona esto, reorganizan su archivo my_calendar.py poniendo la lógica y las pruebas en archivos separados:

    import requests
    from datetime import datetime

    def is_weekday():
    today = datetime.today()
    # Python's datetime library treats Monday as 0 and Sunday as 6
    return (0 <= today.weekday() < 5) def get_holidays(): r = requests.get('http://localhost/api/holidays') if r.status_code == 200: return r.json() return None

    Estas funciones se encuentran ahora en su propio archivo, separarse de sus pruebas. A continuación, deberá volver a crear sus pruebas en un archivo llamado tests.py.

    Hasta este punto, hemos parcheado mono objetos en el archivo en el que existen. parches Monkey es la sustitución de un objeto con otro en tiempo de ejecución. Ahora, vamos a usar el parche () para reemplazar los objetos en my_calendar.py:

    import unittest
    from my_calendar import get_holidays
    from requests.exceptions import Timeout
    from unittest.mock import patch

    class TestCalendar(unittest.TestCase):
    @patch('my_calendar.requests')
    def test_get_holidays_timeout(self, mock_requests):
    mock_requests.get.side_effect = Timeout
    with self.assertRaises(Timeout):
    get_holidays()
    mock_requests.get.assert_called_once()

    if __name__ == '__main__':
    unittest.main()

    Originalmente, se creó una maqueta y parcheado solicitudes en el ámbito local. Ahora, es necesario para acceder a la biblioteca de solicitudes en my_calendar.py de tests.py.

    Para este caso, se utiliza el parche () como decorador y se pasa la ruta del objeto de destino. La ruta de destino era 'my_calendar.requests' que consiste en el nombre del módulo y el objeto.

    También definido un nuevo parámetro para la función de prueba. patch () utiliza este parámetro para pasar el objeto burlado en su prueba. A partir de ahí, se puede modificar la maqueta o hacer afirmaciones como sea necesario.

    Puede ejecutar este módulo de prueba para asegurarse de que está funcionando como se esperaba: Detalle

    $ python tests.py
    .
    -------------------------------------------------------
    Ran 1 test in 0.001s

    OK

    técnico: parche () devuelve una instancia de MagicMock, que es una subclase Mock. MagicMock es útil ya que implementa métodos más magia para usted, como .__ __ len (), str .__ __ (), y .__ __ iter (), con valores por defecto razonables.

    Uso de parche () como un decorador funcionó bien en este ejemplo. En algunos casos, es más fácil de leer, más eficaz, o más fácil el uso del parche () como un gestor de contexto.

    parche

    () como un Contexto Gestor

    A veces, tendrá que utilizar el parche () como un gestor de contexto en lugar de un decorador. Algunas de las razones por las que podría preferir un gestor de contexto incluyen los siguientes:

    • Usted sólo quiere burlarse de un objeto para una parte del volumen de prueba.
    • Usted ya está usando demasiados decoradores o parámetros, lo que perjudica la legibilidad de su prueba.

    Para el uso del parche () como un gestor de contexto, se utiliza Python con la declaración:

    import unittest
    from my_calendar import get_holidays
    from requests.exceptions import Timeout
    from unittest.mock import patch

    class TestCalendar(unittest.TestCase):
    def test_get_holidays_timeout(self):
    with patch('my_calendar.requests') as mock_requests:
    mock_requests.get.side_effect = Timeout
    with self.assertRaises(Timeout):
    get_holidays()
    mock_requests.get.assert_called_once()

    if __name__ == '__main__':
    unittest.main()

    Cuando la prueba sale de la sentencia with, parche () reemplaza el objeto burlado con el original.

    Hasta ahora, has burlado objetos completos, pero a veces sólo se va a querer burlarse de una parte de un objeto.

    Parches un Objeto de Atributos ejemplo de

    permiten sólo quieren burlarse de un método de un objeto en lugar de todo el objeto. Puede hacerlo utilizando patch.object ().

    Por ejemplo, .test_get_holidays_timeout () en realidad sólo necesita requests.get maqueta () y establezca su .side_effect a Tiempo de espera:

    import unittest
    from my_calendar import requests, get_holidays
    from unittest.mock import patch

    class TestCalendar(unittest.TestCase):
    @patch.object(requests, 'get', side_effect=requests.exceptions.Timeout)
    def test_get_holidays_timeout(self, mock_requests):
    with self.assertRaises(requests.exceptions.Timeout):
    get_holidays()

    if __name__ == '__main__':
    unittest.main()

    En este ejemplo, se ha burlado solamente get () en lugar de todas las solicitudes. Cada otro atributo permanece igual.

    objeto () toma los mismos parámetros de configuración que patch () hace. Pero en lugar de pasar el camino del objetivo, se proporciona el objeto de destino, en sí, como el primer parámetro. El segundo parámetro es el atributo del objeto de destino que usted está tratando de burlarse. También puede utilizar el objeto () como un gestor de contexto como el parche ().

    Lectura adicional: Además de objetos y atributos, también se puede parchear los diccionarios () con patch.dict ().

    Aprender a usar el parche () es crítica para burlarse de objetos en otros módulos. Sin embargo, a veces no es obvio lo que el trazado del objeto objetivo.

    Dónde Patch

    saber dónde decirle parche () para buscar el objeto que desea burlado es importante porque si se elige la ubicación de destino equivocado, el resultado de parche () podría ser algo que no esperaba. digamos de

    permiten están burlando de is_weekday () en my_calendar.py usando parche ():

    >>> import my_calendar
    >>> from unittest.mock import patch

    >>> with patch('my_calendar.is_weekday'):
    ... my_calendar.is_weekday()
    ...

    En primer lugar, se importa my_calendar.py. A continuación, aplicar un parche is_weekday (), reemplazándolo con una maqueta. ¡Excelente! Esto funciona como se esperaba.

    Ahora, vamos a cambiar este ejemplo ligeramente y se importan directamente a la función:

    >>> from my_calendar import is_weekday
    >>> from unittest.mock import patch

    >>> with patch('my_calendar.is_weekday'):
    ... is_weekday()
    ...
    False

    Nota: Dependiendo de qué día usted está leyendo este tutorial, su salida de la consola puede leer Verdadero o Falso. Lo importante es que la salida no es un simulacro como antes.

    en cuenta que a pesar de que la ubicación de destino que ha pasado a parche () no cambia, el resultado de llamar is_weekday () es diferente. La diferencia se debe al cambio en la forma en que ha importado la función.

    de my_calendar is_weekday importación se une a la función real del ámbito local. Así, a pesar de que Patch () la función más tarde, se ignora el simulacro porque ya tiene una referencia local a la función anti-burlado.

    Una regla de oro es bien de parchear () del objeto en el que se busca.

    En el primer ejemplo, burlándose 'my_calendar.is_weekday ()' obras, ya que mirar hacia arriba la función en el módulo my_calendar. En el segundo ejemplo, usted tiene una referencia local a is_weekday (). Dado que se utiliza la función que se encuentra en el ámbito local, debe burlarse de la función local:

    >>> from unittest.mock import patch
    >>> from my_calendar import is_weekday

    >>> with patch('__main__.is_weekday'):
    ... is_weekday()
    ...

    Ahora, usted tiene un control firme sobre el poder de parche (). Usted ha visto cómo parchar () objetos y atributos, así como donde parchear ellos.

    A continuación, verá algunos problemas comunes inherentes a burla objeto y las soluciones que ofrece unittest.mock. Los problemas que imita objetos

    Común

    Burlándose pueden introducir varios problemas en sus pruebas. Algunos problemas son inherentes a la burla, mientras que otros son específicos de unittest.mock. Hay que tener en cuenta que existen otros problemas con burla que no se mencionan en este tutorial.

    Los cubiertos aquí son similares entre sí en que el problema que causan es fundamentalmente el mismo. En cada caso, las afirmaciones de las pruebas son irrelevantes. A pesar de la intención de cada maqueta es válida, las mismas no son burla.

    cambios a clases de objetos Interfaces y faltas de ortografía

    y definiciones de funciones cambian todo el tiempo. Cuando la interfaz de un objeto cambia, las pruebas que dependen de una maqueta de ese objeto pueden llegar a ser irrelevante.

    Por ejemplo, puede cambiar el nombre de un método, pero hay que olvidar que una burla de prueba que invoca el método y .assert_not_called (). Después del cambio, .assert_not_called () sigue siendo cierto. La afirmación no es útil, sin embargo, porque el método ya no existe. pruebas irrelevantes

    puede no parecer crítico, pero si son sus únicas pruebas y asumen que funcionan correctamente, la situación podría ser desastroso para su aplicación.

    Un problema específico de Mock es una falta de ortografía que puede romper una prueba. Recordemos que un Mock crea su interfaz cuando accede a sus miembros. Por lo tanto, se le inadvertidamente crear un nuevo atributo si se escribe incorrectamente su nombre.

    Si llama .asert_called () en lugar de .assert_called (), su prueba no plantear una AssertionError. Esto se debe a que ha creado un nuevo método en el objeto simulacro de Python llamado .asert_called () en lugar de evaluar una afirmación real. Detalle

    técnico: Curiosamente, assret es una falta de ortografía especial de aserción. Si se intenta acceder a un atributo que se inicia con assret (o afirman), Mock elevará automáticamente una AttributeError.

    Estos problemas se producen cuando se burlan de los objetos dentro de su propio código base. Un problema diferente se plantea cuando te burlas objetos que interactúan con bases de código externos.

    Los cambios en las dependencias externas

    Imagínese una vez más que el código hace una petición a una API externa. En este caso, la dependencia externa es la API que es susceptible a cambios sin su consentimiento. aislado

    Por un lado, la prueba de las pruebas unitarias componentes de código. Así, burlando el código que hace la solicitud ayuda a poner a prueba sus componentes aislados bajo condiciones controladas. Sin embargo, también presenta un problema potencial.

    Si una dependencia externa cambia su interfaz, sus objetos simulados Python no será válida. Si esto sucede (y el cambio de interfaz es una ruptura), sus pruebas pasarán porque sus objetos simulados han enmascarado el cambio, pero el código de producción se producirá un error.

    Por desgracia, esto no es un problema que unittest.mock proporciona una solución para. Debe ejercer un juicio cuando se burla dependencias externas.

    Los tres de estos problemas puede causar la irrelevancia de prueba y problemas potencialmente costosos ya que amenazan la integridad de los simulacros. unittest.mock le da algunas herramientas para hacer frente a estos problemas.

    evitar problemas más comunes gracias Especificaciones

    Como se mencionó antes, si se cambia una definición de clase o función o atributo se escribe incorrectamente una maqueta del objeto Python, puede causar problemas con sus pruebas.

    Estos problemas se deben a Mock crea atributos y métodos, cuando se accede a ellos. La respuesta a estas cuestiones es prevenir Mock desde la creación de atributos que no se ajusten al objeto que está tratando de burlarse.

    Al configurar una maqueta, se puede pasar un objeto a la especificación del parámetro de especificación. El parámetro spec acepta una lista de nombres o otro objeto y define la interfaz de la maqueta. Si se intenta acceder a un atributo que no pertenece a la especificación, Mock lanzará una AttributeError:

    >>> from unittest.mock import Mock
    >>> calendar = Mock(spec=['is_weekday', 'get_holidays'])

    >>> calendar.is_weekday()

    >>> calendar.create_event()
    Traceback (most recent call last):
    File "", line 1, in
    File "/usr/local/Cellar/python/3.6.5/Frameworks/Python.framework/Versions/3.6/lib/python3.6/unittest/mock.py", line 582, in __getattr__
    raise AttributeError("Mock object has no attribute %r" % name)
    AttributeError: Mock object has no attribute 'create_event'

    Aquí, usted ha especificado que el calendario tiene métodos llamados .is_weekday (.get_holidays) y (). Cuando se accede a .is_weekday (), devuelve un Mock. Cuando se accede a .create_event (), un método que no coincide con la especificación, Mock plantea una AttributeError.

    especificaciones funcionan de la misma manera si se configura el Mock con un objeto: .is_weekday

    >>> import my_calendar
    >>> from unittest.mock import Mock

    >>> calendar = Mock(spec=my_calendar)
    >>> calendar.is_weekday()

    >>> calendar.create_event()
    Traceback (most recent call last):
    File "", line 1, in
    File "/usr/local/Cellar/python/3.6.5/Frameworks/Python.framework/Versions/3.6/lib/python3.6/unittest/mock.py", line 582, in __getattr__
    raise AttributeError("Mock object has no attribute %r" % name)
    AttributeError: Mock object has no attribute 'create_event'

    () está disponible al calendario porque se ha configurado el calendario para que coincida con la interfaz del módulo de my_calendar.

    Además, unittest.mock proporciona métodos convenientes de especificar automáticamente la interfaz de un ejemplo Mock.

    Una forma de implementar las especificaciones automáticos es create_autospec:

    >>> import my_calendar
    >>> from unittest.mock import create_autospec

    >>> calendar = create_autospec(my_calendar)
    >>> calendar.is_weekday()

    >>> calendar.create_event()
    Traceback (most recent call last):
    File "", line 1, in
    File "/usr/local/Cellar/python/3.6.5/Frameworks/Python.framework/Versions/3.6/lib/python3.6/unittest/mock.py", line 582, in __getattr__
    raise AttributeError("Mock object has no attribute %r" % name)
    AttributeError: Mock object has no attribute 'create_event'

    Al igual que antes, el calendario es una instancia Mock cuya interfaz partidos my_calendar. Si estás usando el parche (), puede enviar un argumento para el parámetro Autospec para lograr el mismo resultado:

    >>> import my_calendar
    >>> from unittest.mock import patch

    >>> with patch('__main__.my_calendar', autospec=True) as calendar:
    ... calendar.is_weekday()
    ... calendar.create_event()
    ...

    Traceback (most recent call last):
    File "", line 1, in
    File "/usr/local/Cellar/python/3.6.5/Frameworks/Python.framework/Versions/3.6/lib/python3.6/unittest/mock.py", line 582, in __getattr__
    raise AttributeError("Mock object has no attribute %r" % name)
    AttributeError: Mock object has no attribute 'create_event'

    Conclusión

    Usted ha aprendido mucho acerca de burlarse de los objetos utilizando unittest.mock!

    Ahora, usted es capaz de:

    • Uso Mock a objetos imitarlo en sus pruebas
    • Comprobar los datos de uso para entender cómo usar sus objetos
    • Personalizar valores de retorno y los efectos secundarios parche
    • sus simulacros de objetos () objetos a través de su código base
    • Sede y problemas de evitar con el uso de Python simulacro de objetos

    usted ha construido una base de entender que le ayudará a construir mejores pruebas. Puede utilizar burla a hacerse una idea de su código que usted no habría sido capaz de conseguir de otra manera.

    Os dejo con una exención de responsabilidad final. Cuidado con el uso excesivo de los objetos de imitación!

    Es fácil aprovechar el poder de los objetos de imitación de Python y se burlan tanto que en realidad se reduce el valor de las pruebas.

    Si usted está interesado en aprender más sobre unittest.mock, os animo a leer su excelente documentación.

    Deja un comentario

    Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *