Tutorial 9 - Hora dos Testes¶
A maior parte do desenvolvimento de software não envolve a gravação de um novo código, mas sim a modificação do código existente. Garantir que o código existente continue a funcionar da maneira esperada é uma parte fundamental do processo de desenvolvimento de software. Uma maneira de garantir o comportamento do nosso aplicativo é com um conjunto de testes.
Executar o conjunto de testes¶
Acontece que nosso projeto já tem um conjunto de testes! Quando geramos nosso projeto originalmente, foram gerados dois diretórios de nível superior: src
e tests
. A pasta src
contém o código do nosso aplicativo; a pasta tests
contém nosso conjunto de testes. Dentro da pasta tests
há um arquivo chamado test_app.py
com o seguinte conteúdo:
def test_first():
"An initial test for the app"
assert 1 + 1 == 2
Este é um Pytest caso de teste - um bloco de código que pode ser executado para verificar algum comportamento do seu aplicativo. Nesse caso, o teste é um espaço reservado e não testa nada sobre nosso aplicativo, mas é um teste que podemos executar.
Podemos executar esse conjunto de testes usando a opção --test
do briefcase dev
. Como esta é a primeira vez que estamos executando testes, também precisamos passar a opção -r
para garantir que os requisitos de teste também sejam instalados:
(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 ===============================
Sucesso! Acabamos de executar um único teste que verifica se a matemática Python funciona da maneira esperada (que alívio!).
Vamos substituir esse teste de espaço reservado por um teste para verificar se o nosso método greeting()
se comporta da maneira esperada. Substitua o conteúdo de test_app.py
pelo seguinte:
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"
Isso define dois novos testes, verificando os dois comportamentos que esperamos ver: a saída quando um nome é fornecido e a saída quando o nome está vazio.
Agora podemos executar novamente o conjunto de testes. Dessa vez, não precisamos fornecer a opção -r
, pois os requisitos de teste já foram instalados; precisamos apenas usar a opção --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 ===============================
Excelente! Nosso método utilitário greeting()
está funcionando como esperado.
Desenvolvimento orientado por testes¶
Agora que temos um conjunto de testes, podemos usá-lo para impulsionar o desenvolvimento de novos recursos. Vamos modificar nosso aplicativo para ter uma saudação especial para um determinado usuário. Podemos começar adicionando um caso de teste para o novo comportamento que gostaríamos de ver na parte inferior do test_app.py
:
def test_brutus():
"""If the name is Brutus, a special greeting is provided"""
assert greeting("Brutus") == "BeeWare the IDEs of Python!"
Em seguida, execute o conjunto de testes com esse novo teste:
(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 ==========================
Dessa vez, vemos uma falha no teste - e a saída explica a origem da falha: o teste está esperando a saída «BeeWare the IDEs of Python!», mas nossa implementação de greeting()
está retornando «Hello, Brutus». Vamos modificar a implementação de greeting()
em src/helloworld/app.py
para obter o novo 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 executarmos os testes novamente, veremos que nossos testes foram aprovados:
(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 ===============================
Testes de tempo de execução¶
Até o momento, estamos executando os testes no modo de desenvolvimento. Isso é especialmente útil quando se está desenvolvendo novos recursos, pois é possível iterar rapidamente na adição de testes e na adição de código para que esses testes sejam aprovados. No entanto, em algum momento, você desejará verificar se o seu código também é executado corretamente no ambiente do aplicativo de pacote.
As opções --test
e -r
também podem ser passadas para o comando run
. Se você usar briefcase run --test -r
, o mesmo conjunto de testes será executado, mas dentro do pacote de aplicativos empacotados, e não no seu ambiente de desenvolvimento:
(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 ===============================
Como no caso do briefcase dev --test
, a opção -r
só é necessária na primeira vez em que você executa o conjunto de testes para garantir que as dependências de teste estejam presentes. Nas execuções subsequentes, você pode omitir essa opção.
Você também pode usar a opção --test
em back-ends móveis: - assim, briefcase run iOS --test
e briefcase run android --test
funcionarão, executando o conjunto de testes no dispositivo móvel que você selecionar.
Próximos passos¶
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…