Cobertura de código de Python
Python es uno de los lenguajes de programación más populares disponibles actualmente. Debido a su naturaleza de propósito general, Python encuentra aplicación en varios casos de uso de desarrollo de software que van desde simples scripts hasta servidores web y frameworks como Django.
Sin embargo, al igual que con otros lenguajes de programación, las pruebas siguen siendo uno de los aspectos más importantes del desarrollo de software en Python.
En este post, veremos algunas herramientas para medir y escribir la cobertura de casos de prueba para el código de Python.
Unittest
La biblioteca estándar de Python está pre-construida con un módulo llamado unittest. Inspirado en JUnit y otros marcos de pruebas unitarias de los principales lenguajes de programación, unittest es un marco de pruebas que le permite automatizar las pruebas, la configuración compartida y el código de cierre para las pruebas y más.
Una de las características importantes de unittest es el fixture de prueba, es decir, la configuración necesaria para ejecutar una o más pruebas, y cualquier acción de limpieza asociada. Con el fixture de texto, las actividades, como la creación de bases de datos temporales o proxy, directorios, o el inicio de un proceso de servidor, pueden ser atendidos en un solo lugar.
Tomemos algunos casos de prueba de ejemplo y veamos cómo se implementan utilizando unittest:
importar unittest
clase TestStringMethods(unittest.TestCase):
def test_upper(self):
self.assertEqual(‘foo’.upper(), ‘FOO’)
def test_isupper(self):
self.assertTrue(‘FOO’.isupper())
self.assertFalse(‘Foo’.isupper())
def test_split(self):
s = ‘hola mundo’
self.assertEqual(s.split(), )
# comprueba que s.split falla cuando el separador no es una cadena
con self.assertRaises(TypeError):
s.split(2)
if __name__ == ‘__main__’:
unittest.main()
Crea un caso de prueba subclasificando unittest.TestCase. Luego puede definir pruebas individuales con métodos. Tenga en cuenta que los nombres de los casos de prueba deben comenzar con la palabra test. Esta convención de nomenclatura informa al ejecutor de pruebas sobre qué métodos representan las pruebas.
El ejecutor de pruebas es el componente que orquesta la ejecución de las pruebas y proporciona el resultado al usuario. Su implementación varía y puede utilizar una interfaz gráfica, una interfaz textual, o devolver un valor especial para indicar los resultados de la ejecución de las pruebas.
Pytest
Pytest es un marco de pruebas de Python de terceros. Su objetivo es proporcionar un marco para escribir sus pruebas de manera eficiente, mediante la eliminación de todos los gastos generales para la creación de pruebas. Pytest es compatible con Python 2.7, 3.4, 3.5, 3.6, Jython, PyPy-2.3 en Unix/Posix y Windows.
Veamos cómo empezar con Pytest.En primer lugar, descargue la última versión e instálela mediante pip:
Puede comprobar la versión instalada mediante:
Ahora, tomemos una función de ejemplo y un caso de prueba relacionado.
def func(x):
return x + 1def test_answer():
assert func(3) == 5
La función func toma una entrada x y devuelve un valor x + 1. En el caso de prueba, afirmamos si la función func toma la entrada 3 y devuelve 5. Se espera que este caso de prueba falle. Para ejecutar la prueba simplemente escriba pytest en el directorio que tiene el archivo test_sample.py.
$ pytest
=========================== sesión de prueba se inicia ============================
plataforma linux – Python 3.x.y, pytest-3.x.y, py-1.x.y, pluggy-0.x.y
rootdir: $REGENDOC_TMPDIR, inifile:
collected 1 itemtest_sample.py F ================================= FAILURES =================================
_______________________________ test_answer ________________________________
def test_answer():
> assert func(3) == 5
E assert 4 == 5
E + where 4 = func(3)
test_sample.py:5: AssertionError
========================= 1 falló en 0,12 segundos =========================
Coverage.py
Coverage.py es una de las herramientas de cobertura de código más populares para Python. Utiliza herramientas de análisis de código y ganchos de rastreo proporcionados en la biblioteca estándar de Python para medir la cobertura. Se ejecuta en las principales versiones de CPython, PyPy, Jython y IronPython. Puede utilizar Coverage.py tanto con unittest como con Pytest.
Puede descargar la última versión de Coverage e instalarla manualmente, o puede instalarla con pip as:
Ahora ejecute su programa con coverage as
A continuación, para obtener los datos de cobertura, ejecute
Aquí tiene un ejemplo de salida de datos de cobertura
Name Stmts Miss Cover Missing
——————-
my_program.py 20 4 80% 33-35, 39
mi_otro_módulo.py 56 6 89% 17-23
——————-
TOTAL 76 10 87%
Generar informe en archivo html:
$ coverage html
Este es un ejemplo de informe HTML generado por Coverage.py. Incluye Módulo, sentencias, faltantes, excluidos, ramas, parcial y cobertura.
Pytest-cov
Pytest-cov es un plugin de Python para generar informes de cobertura. Además de las funcionalidades soportadas por el comando de cobertura, también soporta pruebas centralizadas y distribuidas. También soporta la cobertura de los subprocesos.
Una vez que haya escrito los casos de prueba como se requiere con Pytest, puede utilizar Pytest-cov para ejecutar todas las pruebas y reportar la cobertura.
Para empezar, instale Pytest-cov como:
Pruebas centralizadas
Las pruebas centralizadas reportan la cobertura combinada del proceso principal y todos sus subprocesos. Puede ejecutar pruebas centralizadas utilizando,
Pruebas distribuidas
Instalar Pytest-xdist, para el soporte de sistemas distribuidos:
Las pruebas distribuidas pueden realizarse en dos modos, dist configuradas a carga y each. Cuando se establece a la carga, la cobertura combinada de todos los esclavos se reporta mientras la prueba distribuida. Los esclavos pueden estar repartidos en cualquier número de hosts y cada esclavo puede estar ubicado en cualquier lugar del sistema de archivos. Cada esclavo tendrá sus subprocesos medidos.
Para las pruebas distribuidas en cada modo, pytest-cov también informa sobre la cobertura combinada de todos los esclavos. Dado que cada esclavo está ejecutando todas las pruebas, esto permite generar un informe de cobertura combinada para múltiples entornos
Resumen
En este post, hemos aprendido sobre varios frameworks de pruebas unitarias y cobertura de código de Python. Si bien estos frameworks facilitan el proceso de pruebas, aún es necesario escribir las pruebas. Aquí están algunas de las mejores prácticas a tener en cuenta al escribir pruebas unitarias.
- Usa nombres largos y descriptivos. Esto a menudo obvia la necesidad de doctrinas en los métodos de prueba.
- Las pruebas deben ser aisladas. No interactuar con una base de datos real o la red. Utilice una base de datos de prueba separada que se descompone o utiliza objetos simulados.
- Enfóquese en una pequeña parte de la funcionalidad.
- Debe ser rápido, pero una prueba lenta es mejor que ninguna prueba.
- A menudo tiene sentido tener una clase de caso de prueba para una sola clase o modelo.