Teste automatizado com Pytest

Uma tradução do artigo foi preparada especificamente para os alunos do curso Python QA Engineer .




Vivemos uma época em que o software está se movendo muito rapidamente para o mercado. Por isso, o processo de desenvolvimento se torna muito estressante. Altas taxas de implementação de software e entrega rápida parecem uma boa parte do modelo de negócios, mas surge a questão aqui sobre como fornecer software da qualidade certa.

Por que precisamos de testes automatizados


Existem muitas vantagens nos testes automatizados, eis três principais:
Reutilização: Não há necessidade de escrever novos scripts sempre, mesmo quando uma nova versão do sistema operacional é lançada, a menos que haja uma necessidade urgente.
Confiabilidade: as pessoas tendem a cometer erros e os carros as tornam menos prováveis. E eles funcionam mais rápido ao executar etapas / testes repetidos que precisam ser executados continuamente.
Trabalho 24/7: você pode começar a testar a qualquer hora do dia, mesmo que remotamente. Se você começar a testar à noite, ele será executado mesmo enquanto você dorme.

Desenvolvida a ferramenta de teste pytest com recursos completos em Python


Atualmente, existem muitas estruturas e ferramentas para teste. Existem diferentes tipos de estruturas, por exemplo, orientada a dados, orientada a palavras-chave, híbrida, BDD etc. Você pode escolher o que melhor se adapte às suas necessidades.

Devo dizer que Python e pytest ocupam um nicho enorme nesse assunto. O Python e suas ferramentas relacionadas são amplamente utilizados, provavelmente porque são mais acessíveis para pessoas com pouca experiência em programação em comparação com outras linguagens.

A estrutura pytest facilita a gravação de pequenos testes, mas também é dimensionada para oferecer suporte a testes funcionais sofisticados de aplicativos e bibliotecas.

Alguns recursos principais do pytest :

  • Detecção automática de módulos e funções de teste;
  • CLI eficaz para melhorar o controle sobre o que você deseja executar ou pular;
  • Grande ecossistema de plugins de terceiros;
  • Luminárias - tipos diferentes, aplicações diferentes;
  • Trabalhe com a estrutura tradicional de teste de unidade.

Detecção de teste automática e configurável


Por padrão, o pytest espera encontrar testes nos módulos Python cujos nomes começam com test_ ou terminam com _test.py . Além disso, por padrão, espera que os nomes das funções de teste iniciem com o prefixo test_ . No entanto, esse protocolo de detecção de teste pode ser alterado adicionando sua própria configuração a um dos pytest configuração pytest .

 # content of pytest.ini # Example 1: have pytest look for "check" instead of "test" # can also be defined in tox.ini or setup.cfg file, although the section # name in setup.cfg files should be "tool:pytest" [pytest] python_files = check_*.py python_classes = Check python_functions = *_check 

Vejamos uma função de teste muito simples:

 class CheckClass(object): def one_check(self): x = "this" assert 'h' in x def two_check(self): x = "hello" assert hasattr(x, 'check') 

Você notou alguma coisa? Não existe assertEqual ou assertDictEqual , apenas uma assert acessível e compreensível. Não há necessidade de importar essas funções para simplesmente comparar dois objetos. Afirmar é o que o Python já possui e não há necessidade de reinventar a roda.

Código do modelo? Não se preocupe, os equipamentos correm para o resgate!


Veja as funções de teste que testam as operações básicas no programa Wallet:

 // test_wallet.py from wallet import Wallet def test_default_initial_amount(): wallet = Wallet() assert wallet.balance == 0 wallet.close() def test_setting_initial_amount(): wallet = Wallet(initial_amount=100) assert wallet.balance == 100 wallet.close() def test_wallet_add_cash(): wallet = Wallet(initial_amount=10) wallet.add_cash(amount=90) assert wallet.balance == 100 wallet.close() def test_wallet_spend_cash(): wallet = Wallet(initial_amount=20) wallet.spend_cash(amount=10) assert wallet.balance == 10 wallet.close() 

Ah, interessante! Você já reparou? Há muito código padrão. Outra coisa que vale a pena notar é que esse teste faz outra coisa além de testar a parte funcional, por exemplo, criar uma carteira e fechá-la com wallet.close() .

Agora vamos ver como você pode se livrar do código padrão usando os pytest pytest.

 import pytest from _pytest.fixtures import SubRequest from wallet import Wallet #==================== fixtures @pytest.fixture def wallet(request: SubRequest): param = getattr(request, 'param', None) if param: prepared_wallet = Wallet(initial_amount=param[0]) else: prepared_wallet = Wallet() yield prepared_wallet prepared_wallet.close() #==================== tests def test_default_initial_amount(wallet): assert wallet.balance == 0 @pytest.mark.parametrize('wallet', [(100,)], indirect=True) def test_setting_initial_amount(wallet): assert wallet.balance == 100 @pytest.mark.parametrize('wallet', [(10,)], indirect=True) def test_wallet_add_cash(wallet): wallet.add_cash(amount=90) assert wallet.balance == 100 @pytest.mark.parametrize('wallet', [(20,)], indirect=True) def test_wallet_spend_cash(wallet): wallet.spend_cash(amount=10) assert wallet.balance == 10 

Legal, não é? As funções de teste agora são compactas e fazem exatamente o que devem fazer. A carteira é configurada, instalada e fechada usando o wallet da wallet . As luminárias não apenas ajudam a escrever códigos reutilizáveis, mas também adicionam o conceito de compartilhamento de dados. Se você observar atentamente, a quantidade na wallet faz parte dos dados de teste fornecidos externamente pela lógica do teste e não é rigidamente fixada dentro da função.

 @pytest.mark.parametrize('wallet', [(10,)], indirect=True) 

Em um ambiente mais controlado, você pode ter um arquivo com dados de teste, por exemplo test-data.ini em seu repositório ou shell, que pode lê-lo, enquanto sua função de teste pode chamar vários shells para ler dados de teste.

No entanto, é recomendável colocar todos os seus equipamentos em um arquivo conftest.py especial. Este é um arquivo especial no pytest que permite ao teste detectar equipamentos globais.

Mas tenho casos de teste que quero executar em diferentes conjuntos de dados!


Não se preocupe, o pytest possui um recurso interessante para parametrizar seu equipamento. Vejamos um exemplo.

Suponha que seu produto tenha uma CLI gerenciada localmente. Além disso, seu produto possui muitos parâmetros padrão definidos na inicialização e você deseja verificar todos os valores desses parâmetros.

Você pode escrever um caso de teste separado para cada um desses parâmetros, mas com o pytest tudo é muito mais simples!

 @pytest.mark.parametrize(“setting_name, setting_value”, [('qdb_mem_usage', 'low'), ('report_crashes', 'yes'), ('stop_download_on_hang', 'no'), ('stop_download_on_disconnect', 'no'), ('reduce_connections_on_congestion', 'no'), ('global.max_web_users', '1024'), ('global.max_downloads', '5'), ('use_kernel_congestion_detection', 'no'), ('log_type', 'normal'), ('no_signature_check', 'no'), ('disable_xmlrpc', 'no'), ('disable_ntp', 'yes'), ('ssl_mode', 'tls_1_2'),])def test_settings_defaults(self, setting_name, setting_value): assert product_shell.run_command(setting_name) == \ self.”The current value for \'{0}\' is \'{1}\'.”.format(setting_name, setting_value), \ 'The {} default should be {}'.format(preference_name, preference_value) 

Legal, não é? Você acabou de escrever 13 casos de teste (cada um define um valor de configuração diferente) e, no futuro, se você adicionar um novo parâmetro ao seu produto, tudo o que você precisa fazer é adicionar outra tupla.

Como o pytest se integra aos testes de interface do usuário com os testes Selenium e API?


Bem, seu produto pode ter várias interfaces. CLI - como dissemos acima. Semelhante à GUI e API. Antes de implantar seu produto de software, é importante testar todos eles. No software corporativo, onde vários componentes estão interconectados e dependem um do outro, uma mudança em uma parte pode afetar todas as outras.

Lembre-se de que o pytest é apenas uma estrutura para testes fáceis, não um tipo específico de teste. Ou seja, você pode criar testes para a GUI usando o Selenium ou, por exemplo, testes para a API com a biblioteca de requests do Python e executá-los com o pytest .

Por exemplo, em um nível alto, isso pode ser uma verificação da estrutura do repositório.



Como você pode ver na imagem acima, é uma boa oportunidade para separar os componentes:

apiobjects : um bom lugar para criar wrappers para chamar pontos de extremidade da API. Você pode ter um BaseAPIObject e uma classe derivada que atenda aos seus requisitos.

ajudantes : você pode adicionar seus métodos auxiliares aqui.

lib : arquivos de biblioteca que podem ser usados ​​por vários componentes, por exemplo, seus conftest em conftest , pageobjects , etc.

pageobjects : O PageObjects arquitetura PageObjects pode ser usado para criar classes para várias páginas da GUI. Usamos o Webium , que é uma biblioteca de implementações de modelos de objeto de página para Python.

suites : você pode escrever seus próprios conjuntos de verificações pylint para obter códigos, eles ajudarão você a ganhar mais confiança na qualidade do seu código.

testes : você pode catalogar testes com base em suas preferências. Isso facilitará o gerenciamento e a revisão de seus testes.

Trouxe-o apenas para referência, a estrutura do repositório e as dependências podem ser organizadas de acordo com suas necessidades pessoais.

Eu tenho muitos casos de teste e quero que eles sejam executados em paralelo


Você pode ter muitos casos de teste em seu conjunto, e acontece que é necessário executá-los em paralelo e reduzir o tempo geral de execução do teste.

O Pytest oferece um incrível plugin de execução de teste paralelo chamado pytest-xdist , que adiciona vários modos de execução exclusivos ao pytest de base. Instale este plugin usando pip .

 pip install pytest-xdist 

Vamos ver como isso funciona com um exemplo.

Eu tenho um repositório de testes automatizados do CloudApp para meus testes da GUI do Selenium. Além disso, está em constante crescimento e atualização com novos testes e agora possui centenas de testes. O que eu quero fazer é executá-los em paralelo e reduzir o tempo geral de execução do teste.

No terminal, basta digitar pytest na pasta raiz do projeto / pasta de teste. Isso permitirá que você execute todos os testes.

 pytest -s -v -n=2 



pytest-xdist irá executar todos os testes em paralelo!

Dessa forma, você também pode executar vários navegadores em paralelo.

Relatórios


O Pytest vem com suporte interno para a criação de arquivos de resultados de teste que podem ser abertos usando Jenkins, Bamboo ou outros servidores de integração contínua. Use o seguinte:

 pytest test/file/path — junitxml=path 

Isso ajudará a gerar um ótimo arquivo XML que pode ser aberto com muitos analisadores.

Conclusão


A popularidade do Pytest está crescendo a cada ano. Além disso, possui um poderoso suporte da comunidade, que permite acessar muitas extensões, como pytest-django , que o ajudará a escrever testes para aplicativos da web no Django. Lembre-se de que o pytest suporta casos de teste mais unittest; portanto, se você usar o unittest , o pytest deve ser considerado com mais detalhes.

Fontes



Só isso. Vejo você no curso !

Source: https://habr.com/ru/post/pt480186/


All Articles