Tutorial 9 - Prüfzeiten¶
Bei der Softwareentwicklung wird meist kein neuer Code geschrieben, sondern bestehender Code geändert. Die Sicherstellung, dass vorhandener Code weiterhin so funktioniert, wie wir es erwarten, ist ein wichtiger Teil des Softwareentwicklungsprozesses. Eine Möglichkeit, das Verhalten unserer Anwendung sicherzustellen, ist eine Testsuite.
Ausführen der Testsuite¶
Es stellt sich heraus, dass unser Projekt bereits eine Testsuite hat! Als wir unser Projekt ursprünglich erzeugten, wurden zwei Verzeichnisse der obersten Ebene erzeugt: src
und tests
. Der Ordner src
enthält den Code für unsere Anwendung; der Ordner tests
enthält unsere Testsuite. Innerhalb des Ordners tests
befindet sich eine Datei namens test_app.py
mit folgendem Inhalt:
def test_first():
"An initial test for the app"
assert 1 + 1 == 2
Dies ist ein Pytest Testfall - ein Codeblock, der ausgeführt werden kann, um ein bestimmtes Verhalten Ihrer Anwendung zu überprüfen. In diesem Fall ist der Test ein Platzhalter und testet nichts über unsere Anwendung - aber es ist ein Test, den wir durchführen können.
Wir können diese Testsuite mit der Option --test
für briefcase dev
ausführen. Da dies das erste Mal ist, dass wir Tests ausführen, müssen wir auch die Option -r
übergeben, um sicherzustellen, dass die Testanforderungen auch installiert werden:
(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 ===============================
(beeware-venv) $ briefcase dev --test -r
[helloworld] Installing requirements...
...
Installing dev requirements... done
[helloworld] Running test suite in dev environment...
===========================================================================
============================= test session starts ==============================
platform linux -- Python 3.11.0
pytest==7.2.0
py==1.11.0
pluggy==1.0.0
cachedir: /tmp/.pytest_cache
rootdir: /home/brutus
plugins: anyio-3.6.2
collecting ... collected 1 item
tests/test_app.py::test_first PASSED [100%]
============================== 1 passed in 0.01s ===============================
(beeware-venv) C:\...>briefcase dev --test -r
[helloworld] Installing requirements...
...
Installing dev requirements... done
[helloworld] Running test suite in dev environment...
===========================================================================
============================= test session starts ==============================
platform win32 -- Python 3.11.0
pytest==7.2.0
py==1.11.0
pluggy==1.0.0
cachedir: C:\Users\brutus\AppData\Local\Temp\.pytest_cache
rootdir: C:\Users\brutus
plugins: anyio-3.6.2
collecting ... collected 1 item
tests/test_app.py::test_first PASSED [100%]
============================== 1 passed in 0.01s ===============================
Erfolgreich! Wir haben soeben einen einzigen Test durchgeführt, der bestätigt, dass die Python-Mathematik so funktioniert, wie wir es erwartet haben (was für eine Erleichterung!).
Lassen Sie uns diesen Platzhaltertest durch einen Test ersetzen, der überprüft, ob sich unsere Methode Gruß()
so verhält, wie wir es erwarten. Ersetzen Sie den Inhalt von test_app.py
durch den folgenden:
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"
Dies definiert zwei neue Tests, die beiden erwarteten Verhaltensweisen überprüfen: die Ausgabe, wenn ein Name angegeben wird, und die Ausgabe, wenn der Name leer ist.
Wir können nun die Testsuite erneut ausführen. Diesmal brauchen wir die Option -r
nicht, da die Testanforderungen bereits installiert wurden; wir müssen nur die Option --test
verwenden:
(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 ===============================
(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 ===============================
(beeware-venv) C:\...>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 ===============================
Ausgezeichnet! Unsere Utility-Methode Gruß()
funktioniert wie erwartet.
Testgetriebene Entwicklung¶
Jetzt, da wir eine Test-Suite haben, können wir sie nutzen, um die Entwicklung neuer Funktionen voranzutreiben. Ändern wir unsere Anwendung, um eine spezielle Begrüßung für einen bestimmten Benutzer zu erhalten. Wir können damit beginnen, indem wir einen Testfall für das neue Verhalten, das wir gerne sehen möchten, am Ende von test_app.py
hinzufügen:
def test_brutus():
"""If the name is Brutus, a special greeting is provided"""
assert greeting("Brutus") == "BeeWare the IDEs of Python!"
Führen Sie dann die Testsuite mit diesem neuen Test aus:
(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 ==========================
(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, provide a special greeting"""
> 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 ==========================
============================== 2 passed in 0.11s ===============================
(beeware-venv) C:\...>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, provide a special greeting"""
> 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 ==========================
Dieses Mal sehen wir einen Testfehler - und die Ausgabe erklärt die Quelle des Fehlers: der Test erwartet die Ausgabe „BeeWare the IDEs of Python!“, aber unsere Implementierung von Gruß()
gibt „Hallo, Brutus“ zurück. Ändern wir die Implementierung von Gruß()
in src/helloworld/app.py
, um das neue Verhalten zu erhalten:
def greeting(name):
if name:
if name == "Brutus":
return "BeeWare the IDEs of Python!"
else:
return f"Hello, {name}"
else:
return "Hello, stranger"
Wenn wir die Tests noch einmal durchführen, sehen wir, dass die Tests bestanden wurden:
(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 ===============================
(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 ===============================
(beeware-venv) C:\...>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 ===============================
Laufzeittests¶
Bislang haben wir die Tests im Entwicklungsmodus ausgeführt. Dies ist besonders nützlich, wenn Sie neue Funktionen entwickeln, da Sie schnell Tests und Code hinzufügen können, damit diese Tests erfolgreich sind. Irgendwann werden Sie jedoch sicherstellen wollen, dass Ihr Code auch als Anwendungspaket korrekt ausgeführt wird.
Die Optionen --test
und -r
können auch an den Befehl run
übergeben werden. Wenn Sie briefcase run --test -r
verwenden, wird die gleiche Testsuite ausgeführt, allerdings innerhalb des Anwendungspakets und nicht in Ihrer Entwicklungsumgebung:
(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!
(beeware-venv) $ briefcase run --test -r
[helloworld] Finalizing application configuration...
Targeting ubuntu:jammy (Vendor base debian)
Determining glibc version... done
Targeting glibc 2.35
Targeting Python3.10
[helloworld] Updating application code...
Installing src/helloworld... done
Installing tests... done
[helloworld] Updating requirements...
...
[helloworld] Built build/helloworld/linux/ubuntu/jammy/helloworld-0.0.1/usr/bin/helloworld (test mode)
[helloworld] Starting test suite...
===========================================================================
============================= 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 ===============================
(beeware-venv) C:\...>briefcase run --test -r
[helloworld] Updating application code...
Installing src/helloworld... done
Installing tests... done
[helloworld] Updating requirements...
...
[helloworld] Built build\helloworld\windows\app\src\Hello World.exe (test mode)
===========================================================================
Log started: 2022-12-02 10:57:34Z
PreInitializing Python runtime...
PythonHome: C:\Users\brutus\beeware-tutorial\helloworld\windows\app\Hello World\src
PYTHONPATH:
- C:\Users\brutus\beeware-tutorial\helloworld\windows\app\Hello World\src\python311.zip
- C:\Users\brutus\beeware-tutorial\helloworld\windows\app\Hello World\src
- C:\Users\brutus\beeware-tutorial\helloworld\windows\app\Hello World\src\app_packages
- C:\Users\brutus\beeware-tutorial\helloworld\windows\app\Hello World\src\app
Configure argc/argv...
Initializing Python runtime...
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 ===============================
Wie bei briefcase dev --test
wird die Option -r
nur bei der ersten Ausführung der Testsuite benötigt, um sicherzustellen, dass die Testabhängigkeiten vorhanden sind. Bei späteren Durchläufen können Sie diese Option weglassen.
Sie können auch die Option --test
auf mobilen Backends verwenden: - so funktionieren briefcase run iOS --test
und briefcase run android --test
, die Testsuite auf dem von Ihnen ausgewählten mobilen Gerät ausführen.