Voltar PrĂłximo 
Neste capĂtulo, examinaremos os arquivos de configuração que afetam o pytest, discutiremos como o pytest altera seu comportamento com base neles e faremos algumas alterações nos arquivos de configuração do projeto Tarefas.

Os exemplos deste livro foram escritos usando Python 3.6 e pytest 3.2. O pytest 3.2 suporta Python 2.6, 2.7 e Python 3.3+.
O cĂłdigo-fonte do projeto Tarefas, bem como todos os testes mostrados neste livro, estĂŁo disponĂveis no link na página da Web do livro em pragprog.com . VocĂŞ nĂŁo precisa fazer o download do cĂłdigo-fonte para entender o cĂłdigo de teste; o cĂłdigo de teste Ă© apresentado de forma conveniente nos exemplos. Mas, para acompanhar as tarefas do projeto ou adaptar exemplos de teste para testar seu prĂłprio projeto (suas mĂŁos estĂŁo desamarradas!), VocĂŞ deve acessar a página da Web do livro e fazer o download do trabalho. Lá, na página do livro, há um link para mensagens de errata e um fĂłrum de discussĂŁo .
Sob o spoiler, há uma lista de artigos desta série.
Configuração
AtĂ© agora neste livro, falei sobre vários arquivos que nĂŁo sĂŁo de teste que afetam o pytest principalmente de passagem, com a exceção do conftest.py, que abordamos com mais detalhes no CapĂtulo 5, Plugins, na página 95. Neste capĂtulo, examinaremos os arquivos de configuração, que afetam o pytest, discuta como o pytest altera seu comportamento com base neles e faça algumas alterações nos arquivos de configuração do projeto Tarefas.
Noções básicas sobre arquivos de configuração pytest
Antes de dizer como vocĂŞ pode alterar o comportamento padrĂŁo no pytest, vamos examinar todos os arquivos que nĂŁo sĂŁo de teste no pytest e, em particular, quem deve cuidar deles.
VocĂŞ deve saber o seguinte:
- pytest.ini : este Ă© o principal arquivo de configuração do Pytest que permite alterar o comportamento padrĂŁo. Como vocĂŞ pode fazer algumas alterações na configuração, a maior parte deste capĂtulo Ă© dedicada Ă s configurações que vocĂŞ pode fazer no
pytest.ini
. - conftest.py : Este é um plug-in local que permite conectar funções e acessórios de gancho ao diretório em que o arquivo
conftest.py
e a todos os seus subdiretĂłrios. O arquivo conftest.py
descrito no capĂtulo 5 “Plugins” na página 95. __init__.py
: quando colocado em cada subdiretório de teste, esse arquivo permite que você tenha nomes de arquivos de teste idênticos em vários diretórios de teste. Veremos um exemplo do que poderia dar errado sem os arquivos __init__.py
nos diretórios de teste no artigo “Evitando colisões de nomes de arquivos” na página 120.
Se você usa tox, estará interessado em:
- tox.ini : esse arquivo Ă© semelhante ao
pytest.ini
, mas para o tox
. No entanto, você pode colocar sua configuração pytest
vez de ter o arquivo tox.ini
e o arquivo pytest.ini
, economizando um arquivo de configuração. O Tox Ă© discutido no capĂtulo 7, “Usando o pytest com outras ferramentas”, na página 125.
Se você deseja distribuir um pacote Python (por exemplo, Tarefas), este arquivo será do seu interesse:
- setup.cfg : também é um arquivo INI que afeta o comportamento do
setup.py
. VocĂŞ pode adicionar algumas linhas ao setup.py
para executar o python setup.py test
e executar todos os seus testes do pytest. Se você estiver distribuindo o pacote, você já pode ter o arquivo setup.cfg
e pode usá-lo para armazenar a configuração do Pytest. Você verá como isso é feito no Apêndice 4, “Empacotando e distribuindo projetos Python” na página 175.
Não importa em qual arquivo você colocou a configuração pytest, o formato será basicamente o mesmo.
Para pytest.ini
:
ch6 / format / pytest.ini
[pytest] addopts = -rsxX -l --tb=short --strict xfail_strict = true ... more options ...
Para tox.ini
:
ch6 / formato / tox.ini
... tox specific stuff ... [pytest] addopts = -rsxX -l --tb=short --strict xfail_strict = true ... more options ...
Para setup.cfg
:
ch6 / format / setup.cfg
... packaging specific stuff ... [tool:pytest] addopts = -rsxX -l --tb=short --strict xfail_strict = true ... more options ...
A única diferença é que o cabeçalho da seção setup.cfg é [tool:pytest]
vez de [pytest]
.
Listar as opções válidas de arquivo ini com pytest –help
Você pode obter uma lista de todos os parâmetros válidos para pytest.ini
em pytest --help
:
$ pytest --help ... [pytest] ini-options in the first pytest.ini|tox.ini|setup.cfg file found: markers (linelist) markers for test functions empty_parameter_set_mark (string) default marker for empty parametersets norecursedirs (args) directory patterns to avoid for recursion testpaths (args) directories to search for tests when no files or directories are given in the command line. console_output_style (string) console output: classic or with additional progress information (classic|progress). usefixtures (args) list of default fixtures to be used with this project python_files (args) glob-style file patterns for Python test module discovery python_classes (args) prefixes or glob names for Python test class discovery python_functions (args) prefixes or glob names for Python test function and method discovery xfail_strict (bool) default for the strict parameter of xfail markers when not given explicitly (default: False) junit_suite_name (string) Test suite name for JUnit report junit_logging (string) Write captured log messages to JUnit report: one of no|system-out|system-err doctest_optionflags (args) option flags for doctests doctest_encoding (string) encoding used for doctest files cache_dir (string) cache directory path. filterwarnings (linelist) Each line specifies a pattern for warnings.filterwarnings. Processed after -W and --pythonwarnings. log_print (bool) default value for --no-print-logs log_level (string) default value for --log-level log_format (string) default value for --log-format log_date_format (string) default value for --log-date-format log_cli (bool) enable log display during test run (also known as "live logging"). log_cli_level (string) default value for --log-cli-level log_cli_format (string) default value for --log-cli-format log_cli_date_format (string) default value for --log-cli-date-format log_file (string) default value for --log-file log_file_level (string) default value for --log-file-level log_file_format (string) default value for --log-file-format log_file_date_format (string) default value for --log-file-date-format addopts (args) extra command line options minversion (string) minimally required pytest version xvfb_width (string) Width of the Xvfb display xvfb_height (string) Height of the Xvfb display xvfb_colordepth (string) Color depth of the Xvfb display xvfb_args (args) Additional arguments for Xvfb xvfb_xauth (bool) Generate an Xauthority token for Xvfb. Needs xauth. ...
VocĂŞ verá todas essas configurações neste capĂtulo, com exceção dos doctest_optionflags
, discutidos no CapĂtulo 7, “Usando o pytest com outras ferramentas” na página 125.
Os plugins podem adicionar opções de arquivo ini
A lista anterior de configurações nĂŁo Ă© uma constante. Para plugins (e arquivos conftest.py), Ă© possĂvel adicionar opções de arquivos ini. As opções adicionadas tambĂ©m serĂŁo adicionadas Ă saĂda do comando pytest --help.
Agora, vejamos algumas mudanças na configuração que podemos fazer usando as configurações internas do arquivo .ini disponĂveis no core pytest.
Alterar opções de linha de comando padrão
Você já usou algumas opções de linha de comando para o pytest , como -v/--verbose
para saĂda detalhada -l/--showlocals
para visualizar variáveis ​​locais com um rastreamento de pilha para testes com falha. Você pode achar que sempre usa algumas dessas options—or
prefere usá- them—for a project
. Se vocĂŞ instalar addopts
no pytest.ini
para os parâmetros necessários, não precisará mais inseri-los. Aqui está um conjunto que eu gosto:
[pytest] addopts = -rsxX -l --tb=short --strict
A -rsxX
permite que o pytest relate os motivos de todos os testes skipped
, xfailed
ou xpassed
. A opção -l
permite ao pytest exibir um rastreamento de pilha para variáveis ​​locais no caso de cada falha. --tb=short
removerá a maior parte do rastreamento de pilha. No entanto, ele deixará o arquivo e o número da linha. A --strict
proĂbe o uso de tokens se eles nĂŁo estiverem registrados no arquivo de configuração. VocĂŞ verá como fazer isso na prĂłxima seção.
Registro de marcador para evitar erros de digitação de marcadores
Marcadores personalizados, conforme descrito em “Funções de teste de rotulagem” na página 31, sĂŁo Ăłtimos para permitir que vocĂŞ marque um subconjunto de testes para executar com um marcador especĂfico. No entanto, Ă© muito fácil cometer um erro no marcador e, finalmente, alguns testes sĂŁo marcados com @pytest.mark.smoke
e outros sĂŁo marcados com @pytest.mark.somke
. Por padrĂŁo, isso nĂŁo Ă© um erro. O pytest apenas pensa que vocĂŞ criou dois marcadores. No entanto, isso pode ser corrigido registrando tokens no pytest.ini, como por exemplo:
[pytest] ... markers = smoke: Run the smoke test test functions get: Run the test functions that test tasks.get() ...
Ao registrar esses marcadores, agora você também pode vê-los com pytest --markers
com suas descrições:
$ cd /path/to/code/ch6/b/tasks_proj/tests $ pytest --markers @pytest.mark.smoke: Run the smoke test test functions @pytest.mark.get: Run the test functions that test tasks.get() @pytest.mark.skip(reason=None): skip the ... ...
Se os marcadores nĂŁo estiverem registrados, eles nĂŁo aparecerĂŁo na lista --markers
. Quando eles sĂŁo registrados, eles sĂŁo exibidos na lista e, se vocĂŞ usar --strict
, todos os tokens com erros ou não registrados serão exibidos como erros. A única diferença entre ch6/a/tasks_proj
e ch6/b/tasks_proj
Ă© o conteĂşdo do arquivo pytest.ini. Em ch6/a
vazio. Vamos tentar executar os testes sem registrar nenhum marcador:
$ cd /path/to/code/ch6/a/tasks_proj/tests $ pytest --strict --tb=line ============================= test session starts ============================= collected 45 items / 2 errors =================================== ERRORS ==================================== ______________________ ERROR collecting func/test_add.py ______________________ 'smoke' not a registered marker ________________ ERROR collecting func/test_api_exceptions.py _________________ 'smoke' not a registered marker !!!!!!!!!!!!!!!!!!! Interrupted: 2 errors during collection !!!!!!!!!!!!!!!!!!! =========================== 2 error in 1.10 seconds ===========================
Se vocĂŞ usa marcadores no pytest.ini
para registrar seus marcadores, você também pode adicionar --strict
aos seus addopts
enquanto está nisso. Você me agradecerá mais tarde. Vamos em frente e adicione um arquivo pytest.ini ao projeto de tarefas:
Se vocĂŞ usar marcadores no pytest.ini
para registrar seus marcadores, também poderá adicionar --strict
aos seus addopts
. Você me agradecerá mais tarde. Vamos continuar e adicionar o arquivo pytest.ini ao projeto da tarefa:
Se vocĂŞ usar tokens no pytest.ini
para registrar tokens, também poderá adicionar --strict
aos já existentes com addopts
. Legal ?! pytest.ini
agradecimentos e adicione o arquivo pytest.ini
ao projeto de tasks
:
ch6 / b / tasks_proj / tests / pytest.ini
[pytest] addopts = -rsxX -l --tb=short --strict markers = smoke: Run the smoke test test functions get: Run the test functions that test tasks.get()
Aqui está a combinação de sinalizadores preferida por padrão:
-rsxX
para -rsxX
quais testes foram ignorados, xfailed ou xpassed,--tb = short
de um rastreamento mais curto de falhas,--strict
a permitir apenas tokens declarados.
E uma lista de marcadores para o projeto.
Isso deve nos permitir realizar testes, incluindo testes de fumaça:
$ cd /path/to/code/ch6/b/tasks_proj/tests $ pytest --strict -m smoke ===================== test session starts ====================== collected 57 items func/test_add.py . func/test_api_exceptions.py .. ===================== 54 tests deselected ====================== =========== 3 passed, 54 deselected in 0.06 seconds ============
Requisito mĂnimo de Pytest
O parâmetro minversion
permite especificar a versĂŁo mĂnima do pytest esperada para os testes. Por exemplo, pretendia usar approx()
ao testar números de ponto flutuante para determinar a igualdade "razoavelmente próxima" nos testes. Mas essa função não foi introduzida no pytest até a versão 3.0. Para evitar confusão, adiciono o seguinte aos projetos que usam approx()
:
[pytest] minversion = 3.0
Portanto, se alguém tentar executar testes usando uma versão mais antiga do pytest, uma mensagem de erro será exibida.
Pare de pytest de procurar nos lugares errados
Você sabia que uma das definições de "recurse" é jurar duas vezes no seu próprio código? Bem, não. De fato, isso significa contabilizar subdiretórios. O pytest permitirá a detecção de testes examinando recursivamente vários diretórios. Mas existem alguns diretórios que você deseja excluir da exibição do pytest.
O valor padrĂŁo para norecurse
Ă© '. * Build dist CVS _darcs {arch} and *.egg. Having '.*'
'. * Build dist CVS _darcs {arch} and *.egg. Having '.*'
'. * Build dist CVS _darcs {arch} and *.egg. Having '.*'
É um bom motivo para nomear seu ambiente virtual como '.venv', porque todos os diretĂłrios que começam com um ponto nĂŁo estarĂŁo visĂveis.
No caso do projeto Tarefas, o src
não fará mal em especificar, porque pesquisar em arquivos de teste usando pytest será uma perda de tempo.
[pytest] norecursedirs = .* venv src *.egg dist build
Ao substituir um parâmetro que já possui um valor útil, como esse parâmetro, é útil saber quais são os valores padrão e retornar os que você precisa, como fiz no código anterior com a *.egg dist build
.
norecursedirs
Ă© um tipo de consequĂŞncia para os caminhos de teste, entĂŁo vamos dar uma olhada nisso mais tarde.
especificação da árvore de diretórios de teste
Enquanto norecursedirs
diz ao pytest onde procurar, testpaths
diz ao pytest onde procurar. testspaths
é uma lista de diretórios relativos ao diretório raiz para encontrar testes. É usado apenas se o diretório, arquivo ou nodeid
nĂŁo nodeid
especificado como argumento.
Suponha que, para um projeto de Tasks
, colocamos pytest.ini
no diretĂłrio tasks_proj
, em vez de testes:
\code\tasks_proj>tree/f . │ pytest.ini │ ├───src │ └───tasks │ api.py │ ... │ └───tests │ conftest.py │ pytest.ini │ ├───func │ test_add.py │ ... │ ├───unit │ test_task.py │ __init__.py │ ...
EntĂŁo, pode fazer sentido colocar os testes nos testpaths
:
[pytest] testpaths = tests
Agora, se você executar pytest a partir do diretório tasks_proj, o pytest pesquisará apenas em tasks_proj/tests
. O problema aqui é que, durante o desenvolvimento e a depuração de testes, eu frequentemente itero no diretório de teste, para que eu possa testar facilmente um subdiretório ou arquivo sem especificar o caminho inteiro. Portanto, essa opção me ajuda um pouco nos testes interativos.
No entanto, Ă© Ăłtimo para testes em execução a partir de um servidor de integração contĂnua ou tox. Nesses casos, vocĂŞ sabe que o diretĂłrio raiz será corrigido e poderá listar os diretĂłrios relativos a esse diretĂłrio raiz fixo. TambĂ©m sĂŁo esses os casos em que vocĂŞ realmente deseja reduzir o tempo de teste, portanto, Ă© Ăłtimo se livrar da pesquisa de testes.
Ă€ primeira vista, pode parecer bobagem usar os caminhos de teste e os norecursedirs
ao mesmo tempo. No entanto, como você já viu, os caminhos de teste ajudam pouco nos testes interativos de diferentes partes do sistema de arquivos. Nesses casos, os norecursedirs
podem ajudar. Além disso, se você tiver diretórios de teste que não contenham testes, poderá usar norecursedirs
para evitá-los. Mas, na verdade, qual é o sentido de colocar diretórios extras em testes que não têm testes?
Alterando regras de detecção de teste
O pytest encontra testes para executar com base em regras especĂficas de descoberta de testes. Regras padrĂŁo de detecção de teste:
• Comece com um ou mais diretórios. Você pode especificar os nomes de arquivos ou diretórios na linha de comando. Se você não especificou nada, o diretório atual é usado.
• Pesquise o catálogo e todos os seus subdiretórios por módulos de teste.
• Um módulo de teste é um arquivo com um nome semelhante a test_*.py
ou *_test.py
.
• Procure nos módulos de teste as funções que começam com o teste .
Procure classes que começam com Teste. Procure métodos nas classes que começam com `test ,
init` .
Essas são regras de detecção padrão; No entanto, você pode alterá-los.
python_classes
A regra usual para encontrar testes para pytest e classes Ă© considerar uma classe como uma classe de teste em potencial se iniciar com Test*
. A classe também não pode ter o método __init__()
. Mas e se quisermos nomear nossas classes de teste como <something>Test
ou <something>Suite
? É aqui que o python_classes
entra:
[pytest] python_classes = *Test Test* *Suite
Isso nos permite nomear as classes assim:
class DeleteSuite(): def test_delete_1(): ... def test_delete_2(): ... ....
python_files
Como pytest_classes
, python_files
modifica a regra de detecção de teste padrão, que consiste em encontrar arquivos que começam com test_*
ou possuem *_test
no final.
Suponha que vocĂŞ tenha uma estrutura de teste personalizada na qual nomeou todos os seus arquivos de teste como check_<something>.py
. Parece razoável. Em vez de renomear todos os seus arquivos, basta adicionar uma linha ao pytest.ini
seguinte maneira:
[pytest] python_files = test_* *_test check_*
Muito simples Agora você pode transferir gradualmente a convenção de nomenclatura, se desejar, ou simplesmente deixá-la como check_*
.
python_functions
python_functions
atua como as duas configurações anteriores, mas para funções de teste e nomes de métodos. O valor padrão é test_*
. E para adicionar check_*
adivinhou - faça o seguinte:
[pytest] python_functions = test_* check_*
As pytest
nomenclatura pytest
não parecem tão restritivas, não é? Portanto, se você não gosta da convenção de nomenclatura padrão, basta alterá-la. No entanto, peço que você tenha uma razão mais convincente para tais decisões. Migrar centenas de arquivos de teste é definitivamente um bom motivo.
Proibição XPASS
Definir xfail_strict = true
significa que os testes marcados com @pytest.mark.xfail
não são reconhecidos como causadores do erro. Eu acho que essa configuração sempre deve ser. Para obter mais informações sobre o token xfail
consulte “Marcando testes aguardando falha” na página 37.
Evitar conflitos de nome de arquivo
A utilidade de ter o arquivo __init__.py
em cada subdiretório de teste do projeto me confundiu bastante. No entanto, a diferença entre tê-los ou não é simples. Se você tiver arquivos __init__.py
em todos os seus subdiretórios de teste, poderá ter o mesmo nome de arquivo de teste em vários diretórios. E se não, então isso não vai funcionar.
Aqui está um exemplo. Os diretórios b
tĂŞm o arquivo test_foo.py
. NĂŁo importa o que esses arquivos contĂŞm, mas, para este exemplo, eles se parecem com isso:
ch6 / dups / a / test_foo.py
def test_a(): pass
ch6 / dups / b / test_foo.py
def test_b(): pass
Com esta estrutura de diretĂłrios:
dups ├── a │ └── test_foo.py └── b └── test_foo.py
Esses arquivos nem têm o mesmo conteúdo, mas os testes estão corrompidos. Você poderá executá-los separadamente, mas não há como executar o dups
diretĂłrio dups
:
$ cd /path/to/code/ch6/dups $ pytest a ============================= test session starts ============================= collected 1 item a\test_foo.py . ========================== 1 passed in 0.05 seconds =========================== $ pytest b ============================= test session starts ============================= collected 1 item b\test_foo.py . ========================== 1 passed in 0.05 seconds =========================== $ pytest ============================= test session starts ============================= collected 1 item / 1 errors =================================== ERRORS ==================================== _______________________ ERROR collecting b/test_foo.py ________________________ import file mismatch: imported module 'test_foo' has this __file__ attribute: /path/to/code/ch6/dups/a/test_foo.py which is not the same as the test file we want to collect: /path/to/code/ch6/dups/b/test_foo.py HINT: remove __pycache__ / .pyc files and/or use a unique basename for your test file modules !!!!!!!!!!!!!!!!!!! Interrupted: 1 errors during collection !!!!!!!!!!!!!!!!!!! =========================== 1 error in 0.34 seconds ===========================
Nada está claro!
Esta mensagem de erro nĂŁo indica o que deu errado.
Para corrigir esse teste, basta adicionar o arquivo __init__.py
vazio aos subdiretórios. Aqui está um exemplo do diretório dups_fixed
com os mesmos nomes de arquivos duplicados, mas com os arquivos __init__.py
adicionados:
dups_fixed/ ├── a │ ├── __init__.py │ └── test_foo.py └── b ├── __init__.py └── test_foo.py
Agora vamos tentar novamente a partir do nĂvel superior em dups_fixed
:
$ cd /path/to/code/ch6/ch6/dups_fixed/ $ pytest ============================= test session starts ============================= collected 2 items a\test_foo.py . b\test_foo.py . ========================== 2 passed in 0.15 seconds ===========================
Então será melhor.
Obviamente, você pode se convencer de que nunca terá nomes de arquivos duplicados, o que não importa. Tudo, como, é normal. Mas os projetos estão crescendo e os catálogos de testes estão crescendo, e você definitivamente quer esperar que isso aconteça antes de cuidar disso? Eu digo, basta colocar esses arquivos lá. Crie um hábito e não se preocupe com isso novamente.
ExercĂcios
No CapĂtulo 5, Plugins, na página 95, vocĂŞ criou um plugin chamado pytest-nice que incluĂa uma opção de linha de comando --nice. Vamos estender isso para incluir uma opção pytest.ini chamada nice.
No CapĂtulo 5, “Plugins” na página 95, vocĂŞ criou um plugin chamado pytest-nice
que inclui a --nice
linha de comando --nice
. Vamos expandir isso para incluir a opção pytest.ini
chamada nice
.
- Adicione a seguinte linha à função de gancho
pytest_addoption
pytest_nice.py
: parser.addini('nice', type='bool', help='Turn failures into opportunities.')
- Os lugares no plugin que usam
getoption()
também terão que chamar getini('nice')
. Faça essas alterações. - Verifique isso manualmente adicionando
nice
ao arquivo pytest.ini
. - Não se esqueça dos testes de plugins. Adicione um teste para verificar se o
nice
parâmetro do pytest.ini
funcionando corretamente. - Adicione testes ao diretĂłrio do plug-in. VocĂŞ precisa encontrar alguns recursos adicionais do Pytester .
O que vem a seguir
Embora o pytest seja extremamente poderoso por si sĂł - especialmente com plugins -, ele tambĂ©m se integra bem a outras ferramentas de desenvolvimento e teste de software. No prĂłximo capĂtulo, examinaremos o uso do pytest em conjunto com outras poderosas ferramentas de teste.
Voltar PrĂłximo 