Mocking
En el desarrollo de software, las pruebas unitarias son esenciales para garantizar que su código funcione correctamente. Sin embargo, a menudo es necesario simular o "burlarse" de ciertas partes de su código para probar componentes de manera aislada y controlada. Esto se logra mediante el uso de mocks o "mocker" en el contexto de pruebas. En esta guía, exploraremos qué es el "mocking", cómo se aplica en las pruebas unitarias y cómo utilizarlo en conjunto con Pytest, un popular marco de pruebas para Python.
¿Qué es el Mocking en Pruebas Unitarias?
El "mocking" es una técnica que implica simular el comportamiento de ciertas partes de su código para probar componentes de manera aislada. En lugar de usar implementaciones reales, se utilizan objetos simulados o "mocks" que imitan el comportamiento de los objetos reales, pero de manera controlada.
Los "mocks" se utilizan principalmente para:
-
Aislar Componentes: Al simular componentes externos, como bases de datos o servicios web, puede aislar la unidad que está probando y evitar que interactúe con componentes reales durante las pruebas.
-
Controlar Comportamientos: Puede especificar el comportamiento deseado de un "mock" para que se comporte de una manera particular durante una prueba.
-
Simular Condiciones de Error: Puede simular condiciones de error o excepciones lanzadas por un componente para asegurarse de que su código maneje adecuadamente estas situaciones.
Aplicación de Mocking con Pytest
Pytest es un marco de pruebas popular en Python que ofrece soporte integrado para el "mocking" a través de la biblioteca unittest.mock
. A continuación, veremos cómo aplicar el "mocking" en pruebas unitarias con Pytest.
Configuración Inicial
Antes de comenzar a utilizar "mocks" en sus pruebas con Pytest, asegúrese de tener instalado Pytest y la biblioteca unittest.mock
(también conocida como mock
) si aún no las ha instalado:
Ejemplo de Mocking con Pytest
Supongamos que tiene una función que realiza una solicitud HTTP a una API externa y procesa la respuesta. Desea probar esta función sin depender de la API real, por lo que utilizará un "mock" para simular la solicitud HTTP.
Primero, definimos la función que realiza la solicitud HTTP en un módulo llamado api_client.py
:
# api_client.py
import requests
def get_data_from_api(url):
response = requests.get(url)
return response.json()
Luego, escribiremos una prueba unitaria utilizando Pytest y un "mock" para simular la solicitud HTTP. Creamos un archivo de prueba llamado test_api_client.py
:
# test_api_client.py
import pytest
from unittest.mock import Mock
from api_client import get_data_from_api
def test_get_data_from_api(mocker):
# Creamos un mock de requests.get
mock_get = mocker.patch('requests.get')
# Configuramos el comportamiento del mock
mock_get.return_value.json.return_value = {'data': 'mocked_data'}
# Llamamos a la función bajo prueba
result = get_data_from_api('http://example.com/api/data')
# Verificamos que se llamara a requests.get con la URL correcta
mock_get.assert_called_once_with('http://example.com/api/data')
# Verificamos que la función devuelva el valor esperado del mock
assert result == {'data': 'mocked_data'}
En esta prueba:
-
Importamos
pytest
yunittest.mock
(aliasmocker
) para usarlos en la prueba. -
Creamos un "mock" de la función
requests.get
utilizandomocker.patch
. Esto simula la funciónget
de la bibliotecarequests
. -
Configuramos el comportamiento del "mock" para que devuelva un valor simulado cuando se llama a
json
. Esto simula la respuesta de la API. -
Llamamos a la función
get_data_from_api
con la URL, que debería utilizar el "mock" en lugar de realizar una solicitud real. -
Verificamos que la función
requests.get
se llamó una vez con la URL correcta utilizandoassert_called_once_with
. -
Finalmente, verificamos que la función bajo prueba devuelva el valor esperado.
Uso Avanzado de Mocking
El "mocking" con Pytest y unittest.mock
permite una variedad de configuraciones avanzadas, como especificar valores de retorno dinámicos, contar cuántas veces se llama una función y capturar llamadas y argumentos.
Por ejemplo, para especificar un valor de retorno
dinámico, puede usar side_effect
:
# Configurar un mock con un valor de retorno dinámico
mock_get.side_effect = [Exception('Error 1'), {'data': 'mocked_data'}]
Conclusiones
El "mocking" es una técnica poderosa en las pruebas unitarias que le permite controlar el comportamiento de componentes externos y aislar unidades de código para pruebas efectivas. Pytest junto con la biblioteca unittest.mock
hace que el proceso de "mocking" sea más fácil y efectivo en el contexto de las pruebas en Python.
Al utilizar "mocks", puede asegurarse de que sus pruebas se ejecuten de manera controlada y repetible, lo que aumenta la confianza en la calidad de su código y permite identificar y corregir problemas de manera eficiente.