Tutorial 9 - Tiempo de Ejecución del conjunto de pruebas

La mayor parte del desarrollo de software no consiste en escribir código nuevo, sino en modificar el existente. Garantizar que el código existente sigue funcionando de la forma que esperamos es una parte clave del proceso de desarrollo de software. Una forma de asegurar el comportamiento de nuestra aplicación es con un conjunto de pruebas.

Ejecución del conjunto de pruebas

Resulta que nuestro proyecto ya tiene un conjunto de pruebas! Cuando originalmente generamos nuestro proyecto, se generaron dos directorios de nivel superior: src y tests. La carpeta src contiene el código de nuestra aplicación; la carpeta tests contiene nuestro conjunto de pruebas. Dentro de la carpeta tests hay un archivo llamado test_app.py con el siguiente contenido:

def test_first():
    "An initial test for the app"
    assert 1 + 1 == 2

Esto es un Pytest caso de prueba - un bloque de código que puede ser ejecutado para verificar algún comportamiento de tu aplicación. En este caso, la prueba es un marcador de posición, y no verifica nada específico sobre nuestra aplicación, pero es una prueba que podemos realizar.

Podemos ejecutar este conjunto de pruebas utilizando la opción --test de briefcase dev. Como es la primera vez que ejecutamos pruebas, también necesitamos pasar la opción -r para asegurarnos de que también se instalan los requisitos de las pruebas:

(beeware-venv) $ briefcase dev --test -r

[helloworld] Installing requirements...
...
Installing dev requirements... done

[helloworld] Running test suite in dev environment...
===========================================================================
============================= test session starts ==============================
platform darwin -- Python 3.11.0, pytest-7.2.0, pluggy-1.0.0 -- /Users/brutus/beeware-tutorial/beeware-venv/bin/python3.11
cachedir: /var/folders/b_/khqk71xd45d049kxc_59ltp80000gn/T/.pytest_cache
rootdir: /Users/brutus
plugins: anyio-3.6.2
collecting ... collected 1 item

tests/test_app.py::test_first PASSED                                     [100%]

============================== 1 passed in 0.01s ===============================

¡Un éxito! Acabamos de ejecutar una única prueba que verifica que las matemáticas de Python funcionan como esperábamos (¡Qué alivio!).

Vamos a reemplazar esta prueba de marcador de posición con una prueba para verificar que nuestro método greeting() se comporta como esperamos. Sustituye el contenido de test_app.py por el siguiente:

from helloworld.app import greeting


def test_name():
    """If a name is provided, the greeting includes the name"""

    assert greeting("Alice") == "Hello, Alice"


def test_empty():
    """If a name is not provided, a generic greeting is provided"""

    assert greeting("") == "Hello, stranger"

Esto define dos nuevos casos de pruebas, verificando los dos comportamientos que esperamos ver: la salida cuando se proporciona un nombre, y la salida cuando el nombre está vacío.

Ahora podemos volver a ejecutar el conjunto de pruebas. Esta vez, no necesitamos proporcionar la opción -r, ya que los requisitos de la prueba ya se han instalado; sólo tenemos que utilizar la opción --test:

(beeware-venv) $ briefcase dev --test

[helloworld] Running test suite in dev environment...
===========================================================================
============================= test session starts ==============================
...
collecting ... collected 2 items

tests/test_app.py::test_name PASSED                                      [ 50%]
tests/test_app.py::test_empty PASSED                                     [100%]

============================== 2 passed in 0.11s ===============================

Excelente Nuestro método de utilidad greeting() está funcionando como se esperaba.

Desarrollo basado en pruebas

Ahora que tenemos un conjunto de pruebas, podemos utilizarlo para impulsar el desarrollo de nuevas funciones. Vamos a modificar nuestra aplicación para que tenga un saludo especial para un usuario en particular. Podemos empezar por añadir un caso de prueba para el nuevo comportamiento que nos gustaría ver en la parte inferior de test_app.py:

def test_brutus():
    """If the name is Brutus, a special greeting is provided"""

    assert greeting("Brutus") == "BeeWare the IDEs of Python!"

A continuación, ejecute el conjunto de pruebas con esta nueva prueba:

(beeware-venv) $ briefcase dev --test

[helloworld] Running test suite in dev environment...
===========================================================================
============================= test session starts ==============================
...
collecting ... collected 3 items

tests/test_app.py::test_name PASSED                                      [ 33%]
tests/test_app.py::test_empty PASSED                                     [ 66%]
tests/test_app.py::test_brutus FAILED                                    [100%]

=================================== FAILURES ===================================
_________________________________ test_brutus __________________________________

    def test_brutus():
        """If the name is Brutus, a special greeting is provided"""

>       assert greeting("Brutus") == "BeeWare the IDEs of Python!"
E       AssertionError: assert 'Hello, Brutus' == 'BeeWare the IDEs of Python!'
E         - BeeWare the IDEs of Python!
E         + Hello, Brutus

tests/test_app.py:19: AssertionError
=========================== short test summary info ============================
FAILED tests/test_app.py::test_brutus - AssertionError: assert 'Hello, Brutus...
========================= 1 failed, 2 passed in 0.14s ==========================

Esta vez, vemos un fallo en el test - y la salida explica el origen del fallo: el test está esperando la salida «¡BeeWare los IDEs de Python!», pero nuestra implementación de greeting() está devolviendo «Hola, Brutus». Modifiquemos la implementación de greeting() en src/helloworld/app.py para que tenga el nuevo comportamiento:

def greeting(name):
    if name:
        if name == "Brutus":
            return "BeeWare the IDEs of Python!"
        else:
            return f"Hello, {name}"
    else:
        return "Hello, stranger"

Si ejecutamos las pruebas de nuevo, ahora veremos que nuestras pruebas pasan:

(beeware-venv) $ briefcase dev --test

[helloworld] Running test suite in dev environment...
===========================================================================
============================= test session starts ==============================
...
collecting ... collected 3 items

tests/test_app.py::test_name PASSED                                      [ 33%]
tests/test_app.py::test_empty PASSED                                     [ 66%]
tests/test_app.py::test_brutus PASSED                                    [100%]

============================== 3 passed in 0.15s ===============================

Pruebas en tiempo real

Hasta ahora, hemos estado ejecutando las pruebas en modo de desarrollo. Esto es especialmente útil cuando estás desarrollando nuevas características, ya que puedes iterar rápidamente en la adición de pruebas, y la adición de código para hacer que esas pruebas pasen. Sin embargo, en algún momento, usted querrá verificar que su código también se ejecuta correctamente cuando dentro del entorno de aplicación paquete.

Las opciones --test y -r también se pueden pasar al comando run. Si utilizas briefcase run --test -r, se ejecutará el mismo conjunto de pruebas, pero se ejecutará dentro del paquete de aplicaciones empaquetado en lugar de en tu entorno de desarrollo:

(beeware-venv) $ briefcase run --test -r

[helloworld] Updating application code...
Installing src/helloworld... done
Installing tests... done

[helloworld] Updating requirements...
...
[helloworld] Built build/helloworld/macos/app/Hello World.app (test mode)

[helloworld] Starting test suite...
===========================================================================
Configuring isolated Python...
Pre-initializing Python runtime...
PythonHome: /Users/brutus/beeware-tutorial/helloworld/macOS/app/Hello World/Hello World.app/Contents/Resources/support/python-stdlib
PYTHONPATH:
- /Users/brutus/beeware-tutorial/helloworld/macOS/app/Hello World/Hello World.app/Contents/Resources/support/python311.zip
- /Users/brutus/beeware-tutorial/helloworld/macOS/app/Hello World/Hello World.app/Contents/Resources/support/python-stdlib
- /Users/brutus/beeware-tutorial/helloworld/macOS/app/Hello World/Hello World.app/Contents/Resources/support/python-stdlib/lib-dynload
- /Users/brutus/beeware-tutorial/helloworld/macOS/app/Hello World/Hello World.app/Contents/Resources/app_packages
- /Users/brutus/beeware-tutorial/helloworld/macOS/app/Hello World/Hello World.app/Contents/Resources/app
Configure argc/argv...
Initializing Python runtime...
Installing Python NSLog handler...
Running app module: tests.helloworld
---------------------------------------------------------------------------
============================= test session starts ==============================
...
collecting ... collected 3 items

tests/test_app.py::test_name PASSED [ 33%]
tests/test_app.py::test_empty PASSED [ 66%]
tests/test_app.py::test_brutus PASSED [100%]

============================== 3 passed in 0.21s ===============================

[helloworld] Test suite passed!

Al igual que con briefcase dev --test, la opción -r sólo es necesaria la primera vez que se ejecuta el conjunto de pruebas para asegurarse de que las dependencias de prueba están presentes. En las siguientes ejecuciones, puede omitir esta opción.

También puedes utilizar la opción --test en backends móviles: - así briefcase run iOS --test y briefcase run android --test funcionarán, ejecutando el conjunto de pruebas en el dispositivo móvil que selecciones.

Siguientes pasos

We’ve now got a a test suite for our application. But it still looks like a tutorial app. Is there anything we can do about that? Turn to Tutorial 10 to find out…