Testes na trilha de Python

Aprenda a testar seus exercícios de Python no Exercism.


Usamos o pytest como executor de testes do nosso site. Você vai precisar instalar o pytest na sua máquina de desenvolvimento se quiser baixar e rodar os testes dos exercícios da trilha de Python localmente. Você também deve instalar os seguintes plugins do pytest:

Também recomendamos usar o programa de linting de código pylint, porque ele faz parte do nosso feedback automatizado no site e pode ser uma ferramenta de análise estática de código muito útil. Para facilitar, o plugin pytest-pylint do pytest permite rodar o pylint via pytest na linha de comando.

A configuração do Pylint pode ser um pouco complicada, então este tutorial do pylint.readthedocs.io pode ajudar a começar, assim como esta visão geral de Qualidade de código: ferramentas e boas práticas do Real Python.

Instalando o pytest

O pytest pode ser instalado e atualizado usando o utilitário integrado do Python pip.

Para dicas adicionais, Brett Cannon tem um ótimo guia rápido e prático de como instalar pacotes para o Python, junto com uma excelente explicação de por que você deve usar python -m pip. Para saber mais sobre os argumentos de linha de comando do Python, consulte linha de comando e ambiente na documentação do Python.

Nota: Python3 e py podem ou não ser aliases para o Python no seu sistema. Ajuste os comandos de instalação abaixo conforme necessário. Para instalar o pytest em um ambiente virtual, garanta que o ambiente esteja ativado antes de executar os comandos. Caso contrário, a instalação do pytest será global.

Windows

PS C:\Users\foobar> py -m pip install pytest pytest-cache pytest-subtests pytest-pylint
Successfully installed pytest-8.3.3 ...

Linux / MacOS

$ python3 -m pip install pytest pytest-cache pytest-subtests pytest-pylint
Successfully installed pytest-8.3.3 ...

Para verificar se a instalação foi bem-sucedida:

$ python3 -m pytest --version
pytest 8.3.3

Rodando os testes

Para rodar os testes, vá até a pasta onde o exercício está armazenado usando cd no seu terminal (substitua <exercise-folder-location> abaixo pelo seu caminho).

$ cd <exercise-folder-location>

Note

<exercise-folder-location> ou a maioria das coisas entre sinais de maior e menor denota um valor de espaço reservado. Um caminho ou nome de arquivo normal deve ser escrito sem nenhum tipo de sinal desses.

Por exemplo: /Users/janedoe/exercism/python/exercises/concept/chaitanas-colossal-coaster (em sistemas *nix), C:\Users\janedoe\exercism\python\exercises\practice\hello-world\ (no Windows), myFolder ou my_file.py.


O arquivo que você vai querer rodar geralmente termina em _test.py. Esse arquivo contém os testes da solução do exercício, e são os mesmos testes que rodam no site quando uma solução é enviada. Em seguida, rode o seguinte comando no seu terminal, substituindo <exercise_test.py> pelo local/nome do arquivo de teste:

$ python3 -m pytest -o markers=task <exercise_test.py>
==================== 7 passed in 0.08s ====================

Corrigindo avisos

Se você não usar o pytest -o markers=task no comando acima, é possível que você receba warnings sobre "unknown markers" ao rodar um teste que usa a nossa sintaxe nova.

Para evitar digitar pytest -o markers=task em todo teste que você rodar, você pode usar um arquivo de configuração pytest.ini, que pode ser baixado do nível superior do diretório da trilha de Python: pytest.ini.

Você também pode criar seu próprio arquivo pytest.ini com o seguinte conteúdo:

[pytest]
markers =
    task: A concept exercise task.

Colocar esse arquivo no diretório raiz ou de trabalho dos exercícios do Exercism vai registrar as marcas e acabar com os avisos. Você encontra mais informações sobre as marcas do pytest na documentação do pytest sobre marcar funções de teste e na documentação do pytest sobre trabalhar com marcadores personalizados.

Você encontra mais informações sobre como personalizar configurações do pytest na documentação do pytest sobre formatos de arquivo de configuração

Falhas nos testes

Quando os testes falham, o pytest imprime no terminal o texto de cada teste que falhou, junto com os valores esperado e real de return de cada um. Abaixo está um exemplo genérico de um teste que falhou:

$(my_venv) python3 -m pytest -o markers=task <exercise_test.py>

=================== FAILURES ====================
______________ name_of_failed_test ______________
# Test code inside of <exercise_test.py> that failed.
...
E   TypeOfError: ReturnedValue != ExpectedValue

exercise_test.py:<line_of_failed_test>: TypeOfError
============ short test summary info ============
FAILED exercise_test.py::ExerciseTest::name_of_failed_test
========== 1 failed, 2 passed in 0.13s ==========

Argumentos extras

Se você realmente quer ser específico sobre o que o pytest exibe na sua tela, aqui estão alguns argumentos de linha de comando úteis que permitem configurar o comportamento dele.

Mostrar todos os detalhes [-v]

Adicionar a flag -v (verbose) mostra tanto as informações do ambiente quanto um resumo dos testes, além das falhas dos testes:

$(my_venv)  python3 -m pytest -o markers=task -v exercises/<exercise_name>/<test_file_test.py>

======================================== test session starts ===========================================
platform darwin -- Python 3.9.0, pytest-6.2.5, -- /usr/local/envs/my_env/bin/python3
cachedir: .pytest_cache
metadata: {'Python': '3.9.0', 'Platform': 'macOS-10.14.6-x86_64-i386-64bit', 'Packages': {'pytest': '6.2.1'}, 'Plugins': {'subtests': '0.5.0', 'pylint': '0.18.0'}
rootdir: /Users/<user>/exercism/python, configfile: pytest.ini
plugins: subtests-0.5.0, pylint-0.18.0

collected 5 items

exercises/exercise-name/exercise_file_test.py::ExerciseNameTest::test_one FAILED                          [ 20%]
exercises/exercise-name/exercise_file_test.py::ExerciseNameTest::test_two FAILED
exercises/exercise-name/exercise_file_test.py::ExerciseNameTest::test_three PASSED                        [ 40%]
exercises/concept/exercise-name/exercise_file_test.py::ExerciseNameTest::test_four FAILED
exercises/concept/exercise-name/exercise_file_test.py::ExerciseNameTest::test_five PASSED                 [ 60%]
exercises/concept/exercise-name/exercise_file_test.py::ExerciseNameTest::test_six FAILED
exercises/concept/exercise-name/exercise_file_test.py::ExerciseNameTest::test_seven PASSED                [ 80%]
exercises/concept/exercise-name/exercise_file_test.py::ExerciseNameTest::test_eight FAILED
exercises/concept/exercise-name/exercise_file_test.py::ExerciseNameTest::test_nine PASSED                 [100%]

================================================ FAILURES ======================================================
# Failed tests are then individually printed out below

.......

Parar após a primeira falha [-x]

Usar a flag -x roda os testes normalmente, mas interrompe a execução no primeiro teste que falhar. Isso ajuda quando você quer depurar uma única tarefa ou uma única falha de teste por vez:

$(my_venv) python3 -m pytest -o markers=task -x exercises/<exercise_name>/<test_file_test.py>

=================== FAILURES ====================
_______________ example_test_foo ________________
...
...
============ short test summary info ============
FAILED example_test.py::ExampleTest::example_test_foo
!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!
========== 1 failed, 5 passed in 0.28s ==========

Testes que falharam primeiro [--ff]

O plugin pytest-cache lembra quais testes falharam na última vez que você rodou o pytest, então usar a flag --ff diz ao pytest para rodar primeiro os testes que falharam antes, e depois continuar com o restante dos testes. Isso pode acelerar seus testes se você estiver fazendo várias correções pequenas em uma tarefa específica ou em um conjunto de entradas.

$(my_venv) python3 -m pytest -o markers=task --ff <example_file_test.py>
==================== 7 passed in 503s ====================

Fluxo de trabalho recomendado

Recomendamos usar os seguintes comandos para tornar sua depuração mais fácil e (possivelmente) mais rápida:

Primeiro, mude seu diretório de trabalho para o diretório do exercício que você quer testar:

$(my_venv) cd path/to/exercise

Depois, rode os testes junto com os argumentos explicados antes, -x e --ff:

$(my_venv) python3 -m pytest -o markers=task -x --ff <example_file_test.py>

Isso vai testar sua solução. Quando o pytest encontra um teste que falhou, o programa para e diz qual teste falhou. Quando você faz correções e roda o teste de novo, o pytest roda primeiro o teste que falhou antes e depois continua com os testes restantes.

Usando o PDB, o depurador do Python, com o pytest

Se você quer "depurar como um profissional", pode usar o argumento --pdb depois do comando pytest e cair direto no depurador do Python integrado, o PDB.

$(my_venv) python3 -m pytest -o markers=task -x --ff --pdb <example_file_test.py>
=============== 4 passed in 0.15s ===============

Quando um teste falha, entrar no PDB permite percorrer seu código passo a passo, vendo o escopo atual, além de conferir o valor das variáveis e a assinatura de diferentes funções. Você encontra mais detalhes sobre o módulo PDB na documentação do Python sobre o PDB. Além disso, a documentação do pytest sobre o PDB e este guia do Real Python são extremamente úteis.

Estendendo sua IDE

Se você quiser estender sua IDE com algumas ferramentas que vão ajudar a testar e melhorar seu código, veja a página ferramentas. Lá exploramos várias IDEs, editores e algumas extensões úteis para linting e depuração.

Informações adicionais

Adicionando o Python ao seu PATH

Nota: se você instalou o Python no Windows pelo Instalador da PSF, o comando será py em vez de python3.

Digitar python3 -m toda vez que você quer rodar um módulo pode ser um pouco chato. Para evitar isso, você pode adicionar a pasta Scripts da sua instalação do Python ao seu path. Se você não sabe onde instalou o Python, rode o seguinte comando no seu terminal:

$ python3 -c "import os, sys; print(os.path.dirname(sys.executable))"
<python_directory>

O diretório retornado é onde está instalada a sua versão do Python ativa no momento. Nesta seção, ele é chamado de <python_directory>.

Windows

Clique no botão Windows Start e procure por Edit the system environment variables e pressione Enter. Depois, pressione Environment Variables...:

Pressione o botão azul, rs

Depois, encontre a variável Path nas suas User variables, selecione-a e clique em Edit...:

Selecionando a variável path

Depois, adicione uma nova linha, como mostra a figura, substituindo <python_directory> pelo diretório da sua instalação do Python:

Adicionar o Python ao path

MacOS/Linux

O procedimento abaixo deve funcionar na maioria das distribuições Linux e versões do MacOS com um shell bash. Os comandos podem variar conforme a distribuição Linux e conforme o shell usado ser fish ou zsh. Substitua <python_directory> pela saída de python3 -c "import os, sys; print(os.path.dirname(sys.executable))"

export PATH="$PATH:<python_directory>"