Pruebas unitarias de Python: inicio rápido

Se preparó una traducción del artículo específicamente para los estudiantes del curso de Ingeniero de Python QA .


La prueba de código de unidad es una parte integral del ciclo de vida de desarrollo de software. Las pruebas unitarias también forman la base para realizar pruebas de regresión, es decir, garantizan que el sistema se comportará de acuerdo con el escenario cuando se agreguen nuevas características o cambien las existentes.

En este artículo, demostraré la idea básica de las pruebas unitarias en una clase. En la práctica, tendrá que escribir muchos casos de prueba, agregarlos al conjunto de pruebas y ejecutarlos todos juntos. La gestión de casos de prueba se discutirá en el próximo artículo.

Hoy nos centraremos en probar el backend. Es decir, el desarrollador ha implementado algún proyecto de acuerdo con las especificaciones (por ejemplo, Calculator.py), y su tarea es asegurarse de que el código desarrollado realmente coincida con ellos (por ejemplo, usando TestCalculator.py ).

Suponga que escribió la clase Calculadora para realizar funciones computacionales básicas: suma, resta, multiplicación y división.

El código para esto está aquí ( Calculator.py ):

 #A simple calculator class Calculator: #empty constructor def __init__(self): pass #add method - given two numbers, return the addition def add(self, x1, x2): return x1 + x2 #multiply method - given two numbers, return the #multiplication of the two def multiply(self, x1, x2): return x1 * x2 #subtract method - given two numbers, return the value #of first value minus the second def subtract(self, x1, x2): return x1 - x2 #divide method - given two numbers, return the value #of first value divided by the second def divide(self, x1, x2): if x2 != 0: return x1/x2 

Ahora quiero ejecutar una prueba unitaria para comprender que la funcionalidad en la clase anterior funciona según lo planeado.

Python generalmente viene con el paquete unittest . Si no está en su sistema, use pip para instalarlo.

La prueba unitaria tiene la siguiente estructura:



setUp() y tearDown() son métodos estándar que vienen con el marco unittest (se definen en la clase unittest.TestCase). Dependiendo de su caso de prueba, puede anular o no anular estos dos métodos de manera predeterminada.

Es hora de mirar el código del caso de prueba. Aquí está el archivo TestCalculator.py .

 import unittest from Calculator import Calculator #Test cases to test Calulator methods #You always create a child class derived from unittest.TestCase class TestCalculator(unittest.TestCase): #setUp method is overridden from the parent class TestCase def setUp(self): self.calculator = Calculator() #Each test method starts with the keyword test_ def test_add(self): self.assertEqual(self.calculator.add(4,7), 11) def test_subtract(self): self.assertEqual(self.calculator.subtract(10,5), 5) def test_multiply(self): self.assertEqual(self.calculator.multiply(3,7), 21) def test_divide(self): self.assertEqual(self.calculator.divide(10,2), 5) # Executing the tests in the above test case class if __name__ == "__main__": unittest.main() 

Aunque esto no es necesario, pero por regla general, llamo a la clase de prueba con el prefijo Test (en nuestro caso TestCalculator). Un requisito clave en esta clase es la presencia de la superclase unittest.TestCase .

Cada vez que se ejecuta este caso de prueba, el método setUp () se ejecuta primero. En nuestro caso, simplemente creamos un objeto de la clase Calculadora y lo guardamos como un atributo de la clase. Hay varios otros métodos predeterminados en la clase padre, que discutiremos más adelante.

Por ahora, todo lo que hará será escribir métodos test_xxx para probar cada método en la clase Calculadora. Tenga en cuenta que todos los métodos de prueba comienzan con el prefijo test_ . Esto le dice a Python usando el framework unittest que estos son métodos de prueba.

En cada uno de los métodos de prueba, utilicé el método assertEqual para comprobar si los métodos de la calculadora devuelven el valor esperado. Si el valor de retorno es igual al valor esperado, entonces la prueba tiene éxito, de lo contrario falla.

Hay muchos métodos de assert incorporados de los que hablaremos más adelante.

La última línea en el código anterior solo inicia el caso de prueba TestCalculator . Ejecuta cada método de prueba definido dentro de la clase y devuelve el resultado.

 python TestCalculator.py -v 


Verá una conclusión similar a la siguiente:

 test_add (__main__.TestCalculator) ... ok test_divide (__main__.TestCalculator) ... ok test_multiply (__main__.TestCalculator) ... ok test_subtract (__main__.TestCalculator) ... ok -------------------------------------------------------------------- Ran 4 tests in 0.000s OK 

¿Qué pasa si algo no funciona como se esperaba? Cambiemos el valor esperado de test_divide de 5 a 6 (5 es el valor correcto, ahora veremos qué sucede si falla. Esto no es un error en el código fuente, sino un error en el conjunto de pruebas, también puede tener errores en los conjuntos de pruebas, así que siempre verifique prueba scripts para errores!)

 import unittest from Calculator import Calculator #Test cases to test Calulator methods #You always create a child class derived from unittest.TestCase class class TestCalculator(unittest.TestCase): #setUp method overridden from the parent class TestCase def setUp(self): self.calculator = Calculator() ... def test_divide(self): self.assertEqual(self.calculator.divide(10,2), 6) # Executing the tests in the above test case class if __name__ == "__main__": unittest.main() 

Cuando ejecute este caso de prueba, obtendrá el siguiente resultado:

 test_add (__main__.TestCalculator) ... ok test_divide (__main__.TestCalculator) ... FAIL test_multiply (__main__.TestCalculator) ... ok test_subtract (__main__.TestCalculator) ... ok ==================================================================== FAIL: test_divide (__main__.TestCalculator) -------------------------------------------------------------------- Traceback (most recent call last): File "TestCalculator.py", line 23, in test_divide self.assertEqual(self.calculator.divide(10,2), 6) AssertionError: 5.0 != 6 -------------------------------------------------------------------- Ran 4 tests in 0.001s FAILED (failures=1) 

Aquí dice que 3 de 4 pruebas tuvieron éxito, pero una falló. En un escenario real, se supone que su caso de prueba es correcto, es decir, de esta manera ayuda a identificar una función que no se implementa correctamente.

Source: https://habr.com/ru/post/481806/


All Articles