Tutoriel 9 - Temps de test

La plupart des développements de logiciels n’impliquent pas l’écriture d’un nouveau code, mais la modification d’un code existant. S’assurer que le code existant continue à fonctionner comme nous l’attendons est une partie essentielle du processus de développement logiciel. Une façon de s’assurer du comportement de notre application est d’utiliser une suite de tests.

Exécution de la suite de tests

Il s’avère que notre projet possède déjà une suite de tests ! Lorsque nous avons généré notre projet à l’origine, deux répertoires de premier niveau ont été générés : src et tests. Le dossier src contient le code de notre application ; le dossier tests contient notre suite de tests. Dans le dossier tests se trouve un fichier nommé test_app.py avec le contenu suivant: :

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

Ceci est un Pytest test case - un bloc de code qui peut être exécuté pour vérifier un certain comportement de votre application. Dans ce cas, le test est un placeholder, et ne teste rien de notre application - mais c’est un test que nous pouvons effectuer.

Nous pouvons lancer cette suite de tests en utilisant l’option --test de briefcase dev. Comme c’est la première fois que nous lançons des tests, nous devons également passer l’option -r pour nous assurer que les exigences de test sont également installées :

(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 ===============================

Succès ! Nous venons d’exécuter un seul test qui vérifie que les mathématiques Python fonctionnent de la manière attendue (Quel soulagement !).

Remplaçons ce placeholder test par un test pour vérifier que notre méthode greeting() se comporte comme nous l’attendons. Remplacez le contenu de test_app.py par ce qui suit: :

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"

Ceci définit deux nouveaux tests, vérifiant les deux comportements que nous attendons : la sortie lorsqu’un nom est fourni, et la sortie lorsque le nom est vide.

Nous pouvons maintenant réexécuter la suite de tests. Cette fois, nous n’avons pas besoin de fournir l’option -r, puisque les pré-requis pour les tests ont déjà été installés ; nous avons seulement besoin d’utiliser l’option --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 ===============================

Excellent ! Notre méthode utilitaire greeting() fonctionne comme prévu.

Développement piloté par les tests

Maintenant que nous disposons d’une suite de tests, nous pouvons l’utiliser pour développer de nouvelles fonctionnalités. Modifions notre application pour avoir un message d’accueil spécial pour un utilisateur particulier. Nous pouvons commencer par ajouter un scénario de test pour le nouveau comportement que nous aimerions voir au bas 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!"

Ensuite, exécutez la suite de tests avec ce nouveau test :

(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 ==========================

Cette fois, nous voyons un échec du test - et la sortie explique la source de l’échec : le test attend la sortie « BeeWare the IDEs of Python ! », mais notre implémentation de greeting() retourne « Hello, Brutus ». Modifions l’implémentation de greeting() dans src/helloworld/app.py pour avoir le nouveau comportement: :

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

Si nous exécutons à nouveau les tests, nous constatons qu’ils sont réussis :

(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 ===============================

Tests d’exécution

Jusqu’à présent, nous avons exécuté les tests en mode développement. C’est particulièrement utile lorsque vous développez de nouvelles fonctionnalités, car vous pouvez rapidement itérer sur l’ajout de tests et l’ajout de code pour faire passer ces tests. Cependant, à un moment donné, vous voudrez vérifier que votre code s’exécute correctement dans l’environnement de l’application groupée.

Les options --test et -r peuvent également être passées à la commande run. Si vous utilisez briefcase run --test -r, la même suite de tests s’exécutera, mais elle s’exécutera dans le paquetage de l’application plutôt que dans votre environnement de développement :

(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!

Comme pour briefcase dev --test, l’option -r n’est nécessaire que la première fois que vous exécutez la suite de tests pour vous assurer que les dépendances des tests sont présentes. Lors des exécutions suivantes, vous pouvez omettre cette option.

Vous pouvez également utiliser l’option –test` sur les backends mobiles : - ainsi briefcase run iOS –test` et briefcase run android --test fonctionneront tous les deux, lançant la suite de tests sur l’appareil mobile que vous avez sélectionné.

Étapes suivantes

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…