11 mar. 2017

Pruebas unitarias en Python usando mocking y docker

Hace un tiempo escribí un artículo de pruebas unitarias con python usando Docker.  En ese artículo se muestras las distintas opciones de métodos para hacer pruebas unitarias, este caso se enfoca en hacer un mocking de datos (simulación de datos).

Este artículo se basa en el artículo del sitio semaphoreci, el artículo se llama Getting Started with Mocking in Python.

A continuación dejo el código inicial del Dockerfile, de la calculadora.py y de la prueba:

Archivo Dockerfile:


FROM python
WORKDIR /code/

RUN pip3 install --upgrade pip
RUN pip3 install nose
RUN pip3 install nose-cov
RUN pip3 install rednose
RUN pip3 install pytest
RUN pip3 install pytest-cov
RUN pip3 install mock


#EXPOSE 5000

ADD . /code/
COPY . /code/


#CMD nosetests  --with-coverage
#CMD nosetests -sv --rednose
CMD python -m unittest




Archivo docker-compose.yml:

pruebas:
  build: .

  volumes:
    - ".:/code"


Archivo calculadora.py:
#!/usr/bin/env python
#Se importa sqrt de math
from math import sqrt


#Clase calculadora
class Calculadora:
    #Metodo suma de x y y, se evalua si son enteros si no, devuelve error.
    def suma(self,x,y):
        if type(x) == int and type(y) == int:
            return x + y
        else:
            raise TypeError("Invalid type: {} and {}".format(type(x),type(y)))



Archivo calculadora_test.py:


#!/usr/bin/env python3

from unittest import TestCase
from app.calculadora import Calculadora





class TestCalculadora(TestCase):
    def setUp(self):
        self.calc = Calculadora()

    def test_suma_retorna_resultado_correcto(self):
        ##Asegura que sea igual la operacion de suma 2+2 a 4
        respuesta = self.calc.suma(2,4)
        self.assertEqual(respuesta, 6)



Al ejecutar docker-compose up se tiene:

docker-compose up 
Starting tutorialespruebas_pruebas_1
Attaching to tutorialespruebas_pruebas_1
pruebas_1 | .
pruebas_1 | Name                 Stmts   Miss  Cover
pruebas_1 | ----------------------------------------
pruebas_1 | app.py                   0      0   100%
pruebas_1 | app/calculadora.py       6      0   100%
pruebas_1 | unit.py                  0      0   100%
pruebas_1 | ----------------------------------------
pruebas_1 | TOTAL                    6      0   100%
pruebas_1 | ----------------------------------------------------------------------
pruebas_1 | Ran 1 test in 0.022s
pruebas_1 | 
pruebas_1 | OK
tutorialespruebas_pruebas_1 exited with code 0

Ahora se hará un cambio. En vez de llamar a suma a partir de la calculadora se hará una simulación del resultado usando mocking. Para ello el único cambio que se hará es el de calculadora_test.py.

A continuación el código del archivo:

#!/usr/bin/env python3

from unittest import TestCase
from app.calculadora import Calculadora
from unittest.mock import patch



class TestCalculadora(TestCase):
    

    @patch('app.calculadora.Calculadora.suma', return_value=9)
    def test_suma_retorna_resultado_correcto(self,suma):
        self.assertEqual(suma(2,3), 9)




Se importa patch a partir de mock, y se llama al decorador patch  pasando como argumento el método suma de calculadora, donde se le define que va a devolver el valor de 9 sin importar los argumentos de entrada de dicho método.  Luego se ejecuta el método test_suma_retorna_resultado_correcto donde se le pasa suma y se asegura que la suma de 2 y 3 da 9. 



Al ejecutar docker-compose up se tiene el siguiente resultado:

docker-compose up 
Starting tutorialespruebas_pruebas_1
Attaching to tutorialespruebas_pruebas_1
pruebas_1 | .
pruebas_1 | Name                 Stmts   Miss  Cover
pruebas_1 | ----------------------------------------
pruebas_1 | app.py                   0      0   100%
pruebas_1 | app/calculadora.py       7      0   100%
pruebas_1 | unit.py                  0      0   100%
pruebas_1 | unittest/mock.py      1278   1278     0%
pruebas_1 | ----------------------------------------
pruebas_1 | TOTAL                 1285   1278     1%
pruebas_1 | ----------------------------------------------------------------------
pruebas_1 | Ran 1 test in 0.100s
pruebas_1 | 
pruebas_1 | OK


Como e muestra, la prueba pasa sin probemas, la razón es que se está pasando vía mocking el valor que tiene que devolver la suma sin importar la entrada de datos del método a ejecutar.

El código de los distintos archivos se pueden ver en el repositorio de gitlab en la rama mocking.




Publicar un comentario en la entrada