Esercitazione 9 - Tempi di verifica¶
La maggior parte dello sviluppo del software non comporta la scrittura di nuovo codice, ma la modifica di quello esistente. Assicurarsi che il codice esistente continui a funzionare nel modo in cui ci aspettiamo è una parte fondamentale del processo di sviluppo del software. Un modo per garantire il comportamento della nostra applicazione è una serie di test.
Esecuzione della suite di test¶
Si scopre che il nostro progetto ha già una suite di test! Quando abbiamo generato il nostro progetto, sono state generate due directory di primo livello: src
e tests
. La cartella src
contiene il codice della nostra applicazione; la cartella tests
contiene la nostra suite di test. All’interno della cartella tests
c’è un file chiamato test_app.py
con il seguente contenuto:
def test_first():
"An initial test for the app"
assert 1 + 1 == 2
Questo è un Pytest caso di test - un blocco di codice che può essere eseguito per verificare un comportamento dell’applicazione. In questo caso, il test è un segnaposto e non verifica nulla della nostra applicazione, ma è un test che possiamo eseguire.
Possiamo eseguire questa suite di test usando l’opzione --test
di briefcase dev
. Poiché è la prima volta che si eseguono dei test, è necessario inserire anche l’opzione -r
per assicurarsi che anche i requisiti dei test siano installati:
(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 ===============================
Successo! Abbiamo appena eseguito un singolo test che verifica che la matematica di Python funziona nel modo previsto (che sollievo!).
Sostituiamo questo test segnaposto con un test per verificare che il nostro metodo greeting()
si comporti come ci aspettiamo. Sostituire il contenuto di test_app.py
con il seguente:
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"
Questo definisce due nuovi test, che verificano i due comportamenti che ci aspettiamo di vedere: l’output quando viene fornito un nome e l’output quando il nome è vuoto.
Ora possiamo eseguire nuovamente la suite di test. Questa volta non è necessario fornire l’opzione -r
, poiché i requisiti per i test sono già stati installati; è sufficiente usare l’opzione --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 ===============================
(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 ===============================
Eccellente! Il nostro metodo di utilità greeting()
funziona come previsto.
Sviluppo guidato dai test¶
Ora che abbiamo una suite di test, possiamo usarla per guidare lo sviluppo di nuove funzionalità. Modifichiamo la nostra applicazione per avere un saluto speciale per un utente in particolare. Possiamo iniziare aggiungendo un caso di test per il nuovo comportamento che vorremmo vedere in fondo a test_app.py
:
def test_brutus():
"""If the name is Brutus, a special greeting is provided"""
assert greeting("Brutus") == "BeeWare the IDEs of Python!"
Quindi, eseguire la suite di test con questo nuovo 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 ==========================
(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 ==========================
Questa volta, vediamo un fallimento del test e l’output spiega la fonte del fallimento: il test si aspetta l’output «BeeWare the IDEs of Python!», ma la nostra implementazione di greeting()
restituisce «Hello, Brutus». Modifichiamo l’implementazione di greeting()
in src/helloworld/app.py
per avere il nuovo comportamento:
def greeting(name):
if name:
if name == "Brutus":
return "BeeWare the IDEs of Python!"
else:
return f"Hello, {name}"
else:
return "Hello, stranger"
Se eseguiamo nuovamente i test, vedremo che i nostri test passano:
(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 ===============================
Test di runtime¶
Finora abbiamo eseguito i test in modalità di sviluppo. Questo è particolarmente utile quando si sviluppano nuove funzionalità, in quanto si può iterare rapidamente sull’aggiunta di test e sull’aggiunta di codice per far sì che tali test passino. Tuttavia, a un certo punto, si vorrà verificare che il codice venga eseguito correttamente anche nell’ambiente dell’applicazione bundle.
Le opzioni --test
e -r
possono essere passate anche al comando run
. Se si usa briefcase run --test -r
, verrà eseguita la stessa suite di test, ma all’interno del bundle dell’applicazione confezionata e non nell’ambiente di sviluppo:
(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 ===============================
Come per briefcase dev --test
, l’opzione -r
è necessaria solo la prima volta che si esegue la suite di test, per assicurarsi che le dipendenze del test siano presenti. Nelle esecuzioni successive, si può omettere questa opzione.
Si può anche usare l’opzione --test
sui backend mobili: - quindi briefcase run iOS --test
e briefcase run android --test
funzioneranno entrambi, eseguendo la suite di test sul dispositivo mobile selezionato.