Importación simulada de Python

Abid Ullah 21 junio 2023
  1. Importación simulada de Python
  2. Trampas comunes de la burla en Python
  3. Uso básico de Mock en Python
  4. Cómo usar la importación simulada de Python
  5. Dependencias de Python en las pruebas
  6. Objetos simulados de Python
Importación simulada de Python

En este artículo de Python, examinaremos la biblioteca simulada y aprenderemos a usarla de manera efectiva. Comenzaremos con ejemplos simples y luego veremos usos más avanzados.

Aprenderemos los usos y peligros de los objetos simulados y la burla.

Importación simulada de Python

La biblioteca simulada de Python es una de las bibliotecas más populares para pruebas unitarias. Nos permite reemplazar partes de nuestro sistema con objetos simulados y afirmar que se usan como se esperaba.

La burla es una herramienta poderosa, pero a menudo se malinterpreta. Este artículo discutirá qué es burlarse, cómo se puede usar y algunas trampas comunes.

Burlándose en Python

Burlarse es el proceso de reemplazar un objeto real con un objeto falso. El objeto falso se llama mock.

La simulación nos permite probar cómo nuestro código interactúa con otras partes de nuestro sistema sin depender realmente de esas otras partes. Por ejemplo, podemos simular una base de datos para probar cómo interactúa nuestro código con ella sin tener una base de datos.

Cómo usar Mock en Python

La burla se puede utilizar para dos propósitos diferentes:

  1. Para probar el comportamiento de nuestro código

    Por ejemplo, puede simular una base de datos para afirmar que nuestro código la está consultando correctamente.

  2. Para detectar comportamientos que no queremos probar

    Por ejemplo, podríamos simular una base de datos para evitar conectarnos a ella.

El propósito para el que usamos la burla determinará cómo lo usamos.

Comportamiento de prueba

Cuando usamos la simulación para probar el comportamiento, queremos afirmar que nuestro código interactúa con el objeto simulado como se esperaba. El objeto simulado debe tener la misma interfaz que el objeto real para que nuestro código no sepa que es un simulacro.

Podemos usar el método afirmar_llamado_con() para afirmar que se llamó a un método simulado con los argumentos esperados. Por ejemplo, si nos estamos burlando de una base de datos, podríamos afirmar que el método query() se llamó con el SQL correcto.

También podemos usar el método assert_called() para afirmar que se llamó a un método simulado. Esto es útil cuando no nos importan los argumentos o cuando los argumentos son complejos y difíciles de afirmar.

Comportamiento de eliminación

Cuando usamos el simulacro para bloquear el comportamiento, queremos configurar el objeto simulado para que devuelva los valores que espera. Por ejemplo, si nos estamos burlando de una base de datos, podríamos configurar el método query() para devolver una lista de datos ficticios.

Podemos usar el atributo side_effect para configurar un objeto simulado. El efecto_secundario puede ser cualquier valor, incluida una función.

Cuando se llama al simulacro, se devuelve el efecto_lateral.

Por ejemplo, podemos usar un efecto secundario para devolver valores diferentes cada vez que se llama a un simulacro. Esto es útil para simular errores o diferentes comportamientos.

También podemos usar el efecto secundario para generar una excepción. Esto es útil para simular errores.

Trampas comunes de la burla en Python

Hay algunas trampas comunes cuando se usa la burla:

  1. Una trampa es tratar de burlarse demasiado. Burlarse es una herramienta poderosa, pero no es una panacea.

    La simulación es más útil cuando estamos probando el comportamiento de nuestro código, no el comportamiento de todo nuestro sistema.

    Si tratamos de simular demasiado, terminaremos con muchos objetos simulados y nuestras pruebas serán difíciles de mantener. Burlarse solo de los objetos necesarios y usar objetos reales para el resto es mejor.

  2. Otro escollo es burlarse cuando no es apropiado. La simulación es más útil cuando estás probando partes aisladas de tu código.

    Si está probando todo el sistema, generalmente es mejor usar pruebas de integración. Las pruebas de integración son pruebas que ejercitan todo el sistema y son más lentas y costosas de ejecutar, pero más precisas.

  3. Finalmente, un error común es usar simulacros cuando deberíamos usar falsificaciones. Un objeto falso es un objeto que imita a un objeto real pero no tiene la misma interfaz.

Por ejemplo, una base de datos falsa podría devolver datos codificados en lugar de conectarse a una base de datos real. Las falsificaciones ayudan a detectar el comportamiento, pero no son tan útiles para probar el comportamiento.

Uso básico de Mock en Python

El uso más básico de simulacro es reemplazar un objeto con un objeto simulado.

Por ejemplo, supongamos que tiene una función que toma un objeto como argumento y hace algo con él. Tal vez imprime el nombre del objeto.

Código de ejemplo:

def print_name(obj):
    print(obj.name)

Si quisiéramos probar esta función, podríamos crear un objeto con un atributo de nombre y pasarlo a la función.

Código de ejemplo:

class TestObject:
    def __init__(self, name):
        self.name = name


obj = TestObject("Abid")
print_name(obj)

Producción :

Abid

El código funciona, y podemos ver el nombre impreso como Abid. Pero tiene algunos inconvenientes.

Primero, requiere que creemos un objeto real solo para probar. Esto podría no ser un gran problema en este ejemplo simple, pero en un sistema más complejo, puede ser mucho trabajo configurar los objetos necesarios solo para la prueba.

En segundo lugar, este enfoque no es muy flexible. Para probar diferentes comportamientos, debemos crear un nuevo objeto real cada vez.

Por ejemplo, ¿qué pasa si queremos probar qué sucede cuando el objeto no tiene un atributo de nombre?

Código de ejemplo:

class TestObject:
    def __init__(self, name):
        self.name = name


obj = TestObject()
print_name(obj)

Con el objeto real, obtendríamos un error. Pero al usar el objeto de prueba, la salida del código será lo que falta en el código.

Producción :

__init__() missing 1 required positional argument: 'name'

Cómo usar la importación simulada de Python

Para trabajar con una importación simulada con fines de prueba, creemos y exploremos un objeto simulado.

Primero, necesitamos importar la biblioteca mock. La biblioteca mock nos dará la clase mock a partir de la cual podemos hacer nuestros objetos simulados.

Después de importar la biblioteca, llamaremos a nuestra clase simulada y la imprimiremos para ver cómo se ve este objeto simulado.

Código de ejemplo:

from unittest.mock import Mock

mock = Mock()
print(mock)

Producción :

<Mock id='139754809551888'>

La salida del código muestra una representación del objeto simulado, con la cadena de números ID id='139754809551888'.

Ahora exploremos qué podemos hacer con este objeto simulado y cómo podemos usarlo. Bueno, los objetos simulados generalmente se usan para parchear otros objetos en nuestro código.

Cuando decimos parche, significa reemplazar, imitar o burlarse. Son todos iguales.

Recuerda, la esencia de la burla es reemplazar algo lo más parecido posible a lo real. Además, recuerde que al ejecutar nuestra prueba simulada, queremos que sea en un entorno controlado.

Entonces, las decencias externas no hacen que nuestra prueba simulada falle.

Digamos que tenemos una dependencia externa en nuestro código. Usemos json como ejemplo de dependencia externa.

Y es difícil de controlar y tiene un comportamiento que no necesariamente queremos que suceda en nuestra prueba.

Lo que podemos hacer es usar nuestro objeto simulado para parchear esta dependencia. Entonces, antes que nada, necesitamos importar el formato de archivo json.

Luego usaremos el método json.dumps de JSON y le asociaremos un diccionario. Entonces solo estamos usando un método del método de dependencia externa.

Luego parchearemos JSON usando json = simulacro, y el objeto simulado no tiene ningún objeto tonto. Para probar esto, necesitamos imprimir el directorio de json.

Código de ejemplo:

import json

data = json.dumps({"a": 1})
json = mock
print(dir(json))

Producción :

['assert_any_call', 'assert_called', 'assert_called_once', 'assert_called_once_with', 'assert_called_with', 'assert_has_calls', 'assert_not_called', 'attach_mock', 'call_args', 'call_args_list', 'call_count', 'called', 'configure_mock', 'dumps', 'getdoc', 'method_calls', 'mock_add_spec', 'mock_calls', 'reset_mock', 'return_value', 'side_effect']

Podemos ver cadenas de objetos y métodos como salida asociada con el objeto simulado. Y observe que “volcados” no es uno de los métodos en la salida del código.

Dependencias de Python en las pruebas

Si una función para la que estamos escribiendo una prueba unitaria utiliza alguna dependencia, como un módulo de solicitud o fecha y hora. Entonces existe la posibilidad de que nuestra prueba unitaria no siempre obtenga el mismo resultado de la función que se está probando.

Digamos que tenemos una función que usa la biblioteca request y hace algunas solicitudes HTTP. Así que ahora, si ejecutamos nuestra prueba unitaria sin conexión a Internet, fallará y obtendrá un error de conexión de la biblioteca request.

Por eso es mejor probar nuestro código en un entorno controlado para tener control sobre las dependencias impredecibles, donde podemos reemplazar la llamada real a una dependencia con un objeto simulado. Eso nos permitirá ajustar el comportamiento de esa dependencia.

Por ejemplo, en lugar de realizar una solicitud HTTP real, podemos proporcionar una respuesta HTTP ficticia que se devolverá en la función de llamada request.get().

Las dependencias también se falsifican porque un objeto simulado tiene información sobre sus usuarios que se puede ver.

Por ejemplo, si hemos llamado, ¿cuántas veces llamamos o cuántas veces llamamos a una dependencia en particular? Esto puede ayudarnos a escribir nuestras pruebas unitarias más sólidas.

Entonces, ahora exploraremos cómo simular objetos en Python para realizar pruebas.

Objetos simulados de Python

Trabajaremos en dos scripts de Python para comprender mejor los objetos simulados de Python.

  1. función_tirar_dados
  2. burlarse de roll_dice_function

Así que trabajaremos en un código que generará valores aleatorios. Tendrá una simple función_tirar_dados que devuelve un número entero entre un número y otro.

Y proporcionaremos ambos números a nuestra función, roll_dice_function.

Código de ejemplo:

# import library
import random

# define function


def roll_dice_function():
    print("The number is....")
    return random.randint(5, 10)

Así que primero importamos la biblioteca. Luego definimos nuestra función usando la palabra clave def.

Esta función devuelve un número entero entre 5 y 10. Utiliza la función random.randint del módulo random.

Una vez que hayamos terminado con el código de roll_dice_function, escribiremos otro código usando el objeto simulado para probar la roll_dice_function. Sigamos avanzando.

Primero, necesitamos importar la biblioteca de prueba para mock.

# import library
from unittest.mock import Mock
import random

# define function


def roll_dice_function():
    print("The number is....")
    return random.randint(5, 10)

Vamos a ver cómo funciona. Ahora consideraremos la funcionalidad de la función roll_dice_function que creamos anteriormente.

Entonces, cada vez que llamamos a la función, obtenemos un número aleatorio del 5 al 10.

Código de ejemplo:

# import library
from unittest.mock import Mock
import random

# define function


def roll_dice_function():
    print("The number is....")
    return random.randint(5, 10)


roll_dice_function()

Producción :

The number is....
7

Ejecutemos el código nuevamente y veamos qué número obtenemos esta vez.

Producción :

The number is....
5

Entonces, cada vez que llamamos a la función, obtenemos un número aleatorio generado entre 5 y 10.

Ahora, usaremos simulacros para hacer que la función devuelva el mismo valor cada vez que la llamemos.

Crear objeto simulacro

Para crear un objeto mock, debemos crear un objeto de clase simulado definido en la biblioteca mock.

Código de ejemplo:

mock_roll_object = mock.Mock()

Ahora llamaremos al objeto simulado mock_roll_object.

mock_roll_object = mock.Mock()
mock_roll_object

Producción :

<Mock name='mock.Mock()' id='139883130268416'>

Muestra que cuando llamamos al objeto simulado, obtendremos la salida como un objeto simulado. Entonces, esto es lo que pasa con los objetos simulados en general; cada vez que solicitamos objetos simulados, obtenemos un objeto simulado como salida.

Para simplificar, podemos definir algunas cosas en el objeto simulado. Para fines de depuración, podemos definir el nombre.

Código de ejemplo:

mock_roll_object = mock.Mock(name="mocking roll dice")

Entonces, cuando tratamos de depurar nuestra prueba de unidad, ese nombre puede aparecer, lo que puede ayudarnos a depurar.

Producción :

<Mock name='mocking roll dice' id='139883130347136'>

El nombre de nuestro simulacro es mocking roll dice aquí.

Ahora bien, si queremos devolver un valor en particular, tendremos que asignar el valor a return_value. Entonces, obtendremos el mismo número cada vez que llamemos al objeto simulado.

Código de ejemplo:

mock_roll_object = mock.Mock(name="mocking roll dice", return_value=8)

Ahora llamaremos al objeto.

mock_roll_object()

Producción :

8

Obtendremos 8 cada vez que llamemos al objeto simulado. Como hemos asignado 8 a return_value, obtendremos el mismo valor de retorno.

Esperamos que encuentre útil este artículo de Python para comprender cómo usar Mock en Python.

Autor: Abid Ullah
Abid Ullah avatar Abid Ullah avatar

My name is Abid Ullah, and I am a software engineer. I love writing articles on programming, and my favorite topics are Python, PHP, JavaScript, and Linux. I tend to provide solutions to people in programming problems through my articles. I believe that I can bring a lot to you with my skills, experience, and qualification in technical writing.

LinkedIn

Artículo relacionado - Python Mock