Mclibre Python Testing, comprobador de ejercicios

He empezado a crear Mclibre Python Testing en enero de 2019 y a lo largo del tercer trimestre del curso 2018/19 espero ir mejorando la herramienta, pero todavía tiene un carácter experimental.

Qué es Mclibre Python Testing

Mclibre Python Testing es una herramienta basada en PyTest pensada para ayudar a los alumnos a comprobar que han resuelto correctamente los ejercicios propuestos en este curso.

Mclibre Python Testing es software libre publicado bajo licencia AGPLv3+. El código fuente de esta herramienta se encuentra en GitHub y el programa se distribuye a través del Python Package Index (PyPI).

La herramienta tiene dos partes:

El alumno sólo necesita instalar el programa cliente. El programa cliente requiere las bibliotecas PyTest y Requests, que se deben instalar previamente, como se comenta en la lección Instalación de MPTC.

¿Cómo se utiliza Mclibre Python Testing Client?

En la lección Instalación de Mclibre Python Testing Client (MPTC) se comentan las diferentes opciones de instalación (como módulo de sistema o en entorno virtual) en diferentes sistemas operativos (Windows o Ubuntu).

Una vez instalado MPTC, su uso es sencillo. Los pasos a realizar serían los siguientes:

  1. Elegir un ejercicio que incluya el identificador MPTC del ejercicio:

    Los ejercicios para los que hay disponibles tests automáticos de MPTC se pueden identificar por el cuadro situado en la parte superior derecha del enunciado, como en el ejemplo siguiente:

    Ejemplo de ejercicio - 1

    Escriba un programa que salude al mundo.

    ¡Hola, mundo!
    

    El número del cuadro indica el identificador del ejercicio en MPTC. En el ejemplo anterior, el número sería 1001.

  2. Escribir el programa:

    Escriba el programa que resuelve el ejercicio, siguiendo la plantilla de la lección Programa básico. Este punto es muy importante, ya que sólo se pueden validar los programas que siguen esta plantilla.

    El programa correspondiente al ejemplo anterior podría ser el siguiente:

    def main():
        print("¡Hola, mundo!")
    
    
    if __name__ == "__main__":
        main()
    
  3. Abrir una ventana de terminal en el directorio que contiene el programa.

    Este punto es muy importante, ya que sólo se pueden validar los programas desde el directorio que contiene el programa.

     
    
  4. Comprobar el funcionamiento del programa manualmente:

    Compruebe que el programa funciona correctamente ejecutando el programa (escriba la orden python nombre_del_programa.py, donde nombre_del_programa.py es el nombre del programa) y comparando el resultado con el enunciado.

    python p_1001.py
    ¡Hola, mundo!
    
    
  5. Comprobar el funcionamiento del programa con MPTC

    En el terminal, escriba la orden mptc nombre_del_programa.py identificador_mptc, donde nombre_del_programa.py es el nombre del programa e identificador_mptc es el identificador MPTC del ejercicio:

    mptc p_1001.py 1001
    

    En el terminal, MPTC muestra tres grupos de mensajes:

    • En el primer grupo (WELCOME), MPTC informa del número de tests que se van a realizar.
    • En el segundo grupo (TESTS EXECUTION), MPTC informa del resultado de cada test a medida que se van ejecutando.
    • En el tercer grupo, MPTC (RESULTS), MPTC muestra un resumen del resultado final.
      mptc p_1001.py 1001
    -+-+-+-+-+-+-+-+- MCLIBRE PYTHON TESTING -+-+-+-+-+-+-+-+-
    -+-+-+-+-+-+-+-+-        WELCOME         -+-+-+-+-+-+-+-+-
    
    1 test will be executed.
    
    Please, wait until all tests have been executed.
    
    A final report will be shown after.
    
    -+-+-+-+-+-+-+-+-     TESTS EXECUTION    -+-+-+-+-+-+-+-+-
    
    Running test 1. Please wait.
    Test 1 passed.
    
    -+-+-+-+-+-+-+-+- MCLIBRE PYTHON TESTING -+-+-+-+-+-+-+-+-
    -+-+-+-+-+-+-+-+-         RESULTS        -+-+-+-+-+-+-+-+-
    
    Tested program: p_1001.py
    MPTC number:    1001
    
    1 test has been executed.
    
    All tests have been passed. Congratulations!
    
    
    
  6. Corregir en su caso los errores detectados

    En caso de que falle alguno de los tests, MPTC muestra información sobre el error producido, que puede utilizarse para corregir el error.

    Por ejemplo, si el programa probado hubiera sido el siguiente:

    def main():
        print("Hola, mundo")
    
    
    if __name__ == "__main__":
        main()
    

    ... en el terminal, MPTC hubiera mostrado el siguiente resultado, que nos indica que el mensaje mostrado por el programa no es exactamente igual al solicitado en el enunciado (en este caso, faltan los signos de exclamación):

    mptc p_1001.py 1001
    -+-+-+-+-+-+-+-+- MCLIBRE PYTHON TESTING -+-+-+-+-+-+-+-+-
    -+-+-+-+-+-+-+-+-        WELCOME         -+-+-+-+-+-+-+-+-
    
    1 test will be executed.
    
    Please, wait until all tests have been executed.
    
    A final report will be shown after.
    
    -+-+-+-+-+-+-+-+-     TESTS EXECUTION    -+-+-+-+-+-+-+-+-
    
    Running test 1. Please wait.
    Test 1 failed.
    
    -+-+-+-+-+-+-+-+- MCLIBRE PYTHON TESTING -+-+-+-+-+-+-+-+-
    -+-+-+-+-+-+-+-+-         RESULTS        -+-+-+-+-+-+-+-+-
    
    Tested program: p_1001.py
    MPTC number:    1001
    
    1 test has been executed.
    0 test has been passed.
    1 test has been failed.
    
    Failed test:
      Expected result: "¡Hola, mundo!"
      Obtained result: "Hola, mundo"
    
    
    

¿Cómo funciona Mclibre Python Testing Client (MPTC)?

Cuando se invoca Mclibre Python Testing Client (MPTC) realiza las siguientes operaciones:

Limitaciones de MPTC

MPTC no realiza un análisis del programa, simplemente comprueba que la salida del programa coincide con la esperada para unos valores determinados de entrada.

Si un programa supera todas las pruebas de MPTC, el alumno puede considerar que su programa es muy probablemente correcto, pero no es una garantía absoluta de que el programa no contenga errores. Puede que el programa no funcione correctamente para ciertos valores de entrada que no se han probado o que genere valores aleatorios incorrectos.

Por otro lado, que un programa no supere las pruebas no significa necesariamente que el programa sea incorrecto. En la mayoría de los casos, cuando un programa trabaja a partir de valores introducidos por el usuario, sí que el fallo en una prueba corresponde a un fallo del programa, pero cuando el programa genera valores aleatorios, puede que el fallo de las pruebas no corresponda a un fallo del programa.


Por ejemplo, imaginemos un ejercicio que pide simplemente mostrar un valor de un dado. La solución podría ser el siguiente programa:

import random


def main():
    dado = random.randrange(1, 7)
    print(f"Ha sacado un {dado}.")


if __name__ == "__main__":
  main()

La prueba MPTC podría consistir en este caso en inyectar un valor aleatorio del uno al seis y comprobar que ese valor se muestra al usuario. Se podrían realizar incluso seis pruebas distintas, inyectando en cada prueba uno de los valores del 1 al 6.

Sin embargo, consideremos el siguiente programa:

import random


def main():
    dado = random.randrange(1, 6)
    print(f"Ha sacado un {dado}.")


if __name__ == "__main__":
  main()

Este programa superaría las pruebas MPTC igual que el programa anterior y sin embargo no es correcto, ya que este programa no mostraría nunca el valor 6. Como MPTC sustituye los valores aleatorios generados por el programa por los valores de la prueba, MPTC no puede darse cuenta de que el programa nunca genera el valor 6, porque al inyectar MPTC el valor 6, el programa escribiría el valor 6 correctamente. El problema es que el programa nunca genera el valor 6.

Consideremos ahora el siguiente programa:

import random


def main():
    dado = random.randrange(0, 6)
    print(f"Ha sacado un {dado + 1}.")


if __name__ == "__main__":
  main()

Este programa es correcto porque mostraría siempre un valor entre 1 y 6 y sin embargo al pasarle las pruebas MPTC todas las pruebas fallarían. ¿Por qué? Porque al inyectar un valor, por ejemplo 5, MPTC espera que se escriba que se ha sacado un 5, pero este programa escribiría que se ha sacado un 6. El programa es correcto porque genera valores de 0 a 5 y escribe uno más del valor generado, pero como los valores inyectados van del 1 al 6, los resultados no coinciden con los valores inyectados.

El alumno debe ser consciente de estas limitaciones y utilizar MPTC como lo que es, una herramienta de ayuda para la prueba de programas, pero no como un oráculo infalible.

Cómo utilizar MPTC en Visual Studio Code

Los pasos para utilizar Mclibre Python Testing Client en Visual Studio Code son los siguientes:

Protección de datos

El único dato que el cliente envía al servidor es el número de ejercicio, imprescindible para poder suministrar al cliente los valores de prueba.

Una vez recibidos los valores de prueba, esta se realiza en el ordenador del cliente. El cliente no envía el programa que se va a probar, ni los resultados de las pruebas.

Detalles a tener en cuenta

Si el primer argumento no es únicamente el nombre del fichero, MPTC no ejecuta los tests

Al llamar a MPTC, el primer argumento debe ser el nombre del fichero que contiene el programa. No pueden usarse ni caminos relativos ni absolutos. Si se utilizan caminos absolutos o relativos, se mostrará un mensaje de error, como en el ejemplo siguiente:

PS C:\Users\Barto\Documents\LMSGI Barto\Python\>mptc pruebas\ejemplo_mptc_1000.py 1000
Error: Relative or absolute paths [pruebas\ejemplo_mptc_1000.py] are not allowed.
Please, execute MPTC from the directory where your program is located.