Frameworks de testes: JUnit, PyTest, Selenium, Cypress ou Robot Framework
Testes de software são fundamentais para avaliar e garantir que um produto ou aplicação esteja funcionando conforme esperado. Realizar testes adequados traz benefícios significativos, como a prevenção de alguns bugs e a melhoria no desempenho do sistema. Eles desempenham um papel crucial na identificação precoce de falhas, no aprimoramento da qualidade do código, no aumento da confiança nas mudanças implementadas e na redução do risco de erros em produção.
Nesse contexto, os testes automatizados se tornam muito úteis, pois contribuem para um ciclo de desenvolvimento mais ágil, facilitando a manutenção e a escalabilidade do software. Dessa forma, a adoção de frameworks de testes torna o desenvolvimento mais eficiente e auxilia o software a cumprir os requisitos de qualidade, desempenho e segurança.
Frameworks como JUnit, PyTest, Selenium, Cypress e Robot Framework são ferramentas de automação que ajudam a assegurar a qualidade e confiabilidade dos softwares. Esses frameworks possibilitam a verificação contínua do comportamento das aplicações e a detecção rápida de falhas.
O JUnit, por exemplo, é amplamente utilizado para testes unitários em Java, permitindo que os desenvolvedores validem pequenas unidades de código. O PyTest, popular no ecossistema Python, oferece uma sintaxe simples e eficiente para testes unitários e de integração. Já o Selenium e o Cypress são ferramentas voltadas para testes de interfaces web, sendo o Selenium indicado para testes em múltiplos navegadores, enquanto o Cypress se destaca em testes rápidos e em tempo real. Por fim, o Robot Framework é uma ferramenta genérica para automação de testes, permitindo a execução de testes de aceitação de forma estruturada, podendo ser utilizado em diversas linguagens de programação.
Neste tutorial, iremos detalhar os conceitos relacionados ao framework PyTest.
PyTest
[editar | editar código]O Pytest é um framework de teste para python criado para facilitar a escrita de testes. É uma ferramenta amplamente usada, com uma estrutura de código aberto que permite aos desenvolvedores escrever conjuntos de testes simples e compactos, ao mesmo tempo que oferece suporte a testes de unidade, testes funcionais e testes de API.
Instalação
[editar | editar código]É necessário já ter previamente instalado o Python 3.8+ ou PyPy3.
Para instalar o Pytest, execute o seguinte comando:
pip install -U pytest
Para checar se a instalação foi concluída com sucesso, execute:
pytest --version
Arquivos de teste
[editar | editar código]Ao executar o comando Pytest dentro do ambiente virtual Python, o framework realizará uma varredura nos diretórios e subdiretórios do repositório, buscando arquivos que sigam o padrão de nomenclatura test_*.py ou *_test.py . Por isso, é importante seguir esse padrão.
Teste de Funções
[editar | editar código]
Para que o Pytest colete o teste e o execute, as funções de teste devem ser prefixadas com test_ . Confira a seguir um exemplo de um teste contido no arquivo test_sample.py:
def func(x):
return x + 1
def test_answer():
assert func(3) == 5
Classes de teste e métodos de teste
[editar | editar código]As classes e os métodos de teste também possuem convenções para nomenclatura:
- As classes de teste têm o prefixo
Test - Os métodos de teste têm o prefixo
test_
Veja abaixo um exemplo de teste válido:
class TestClass:
def test_one(self):
x = "this"
assert "h" in x
def test_two(self):
x = "hello"
assert hasattr(x, "check")
Execução de teste
[editar | editar código]O Pytest oferece várias opções para executar e selecionar testes, seja pela linha de comando ou por meio de um arquivo.
Executar testes em um módulo
pytest test_mod.py
Executar testes em um diretório
pytest testing/
Executar testes por argumentos
Para isso, é preciso informar o nome do arquivo do módulo relativo ao diretório de trabalho, seguido por especificadores como o nome da classe e da função, separados por ::, e parâmetros entre [].
Para executar um teste específico dentro de um módulo:
pytest tests/test_mod.py::test_func
Para executar todos os testes em uma classe:
pytest tests/test_mod.py::TestClass
Especificando um método de teste específico:
pytest tests/test_mod.py::TestClass::test_method
Especificando uma parametrização específica de um teste:
pytest tests/test_mod.py::test_func[x1,y2]
Utilização do import
[editar | editar código]
É possível manter os scripts e testes em arquivos diferentes. Para isso, basta adicionar a instrução import. No exemplo a seguir, temos dois arquivos: calcualte_age.py, que calcula a idade do usuário, e test_calculate_age.py:
# calcualte_age.py
import datetime
def get_age(yyyy:int, mm:int, dd:int) -> int:
dob = datetime.date(yyyy, mm, dd)
today = datetime.date.today()
age = round((today - dob).days / 365.25)
return age
# test_calculate_age.py
from calculate_age import get_age
def test_get_age():
# Given.
yyyy, mm, dd = map(int, "2001/07/11".split("/"))
# When.
age = get_age(yyyy, mm, dd)
# Then.
assert age == 23
Instrução assert
[editar | editar código]
O Pytest permite o uso do assert para verificar expectativas e valores em testes Python. Confira o seguinte exemplo:
# content of test_assert1.py
def f():
return 3
def test_function():
assert f() == 4
Execução:
pytest test_assert1.py
Saída:
=========================== test session starts ============================
platform linux -- Python 3.x.y, pytest-8.x.y, pluggy-1.x.y
rootdir: /home/sweet/project
collected 1 item
test_assert1.py F [100%]
================================= FAILURES =================================
______________________________ test_function _______________________________
def test_function():
> assert f() == 4
E assert 3 == 4
E + where 3 = f()
test_assert1.py:6: AssertionError
========================= short test summary info ==========================
FAILED test_assert1.py::test_function - assert 3 == 4
============================ 1 failed in 0.12s =============================
Na saída, algumas métricas são apresentadas e é indicado se o teste falhou ou obteve sucesso.
.sinaliza que o teste foi aprovado;Fsinaliza que houve falha;
Além disso, com o uso do assert, é possível obter uma descrição melhor sobre a divergência encontrada.
Instrução pytest.raises
[editar | editar código]Atua como um gerenciador de contexto, que capturará a exceção do tipo fornecido para afirmar que a exceção acontece. Exemplo:
def test_div_zero_exception():
"""
pytest.raises can assert that exceptions are raised (catching them)
"""
with pytest.raises(ZeroDivisionError):
x = 1 / 0
Neste caso, o teste terá sucesso. Se realizarmos uma modificação para x = 1 / 1 , o teste irá falhar pois a exceção esperada não acontecerá.
Parametrização e a instrução @pytest.mark.parametrize
[editar | editar código]Vamos analisar o código abaixo:
def test_eval_addition():
assert eval("2 + 2") == 4
def test_eval_subtraction():
assert eval("2 - 2") == 0
def test_eval_multiplication():
assert eval("2 * 2") == 4
def test_eval_division():
assert eval("2 / 2") == 1.0
Embora essa solução funcione, ela não é a mais eficiente, pois envolve um grande volume de código repetitivo. Uma abordagem melhor para resolver esse problema é utilizar o @pytest.mark.parametrize, que permite a parametrização de argumentos em uma função de teste. Com isso, podemos definir uma única função de teste e deixar o PyTest testar automaticamente os diferentes parâmetros que especificarmos. Assim, é possível reescrever o código acima como:
import pytest
@pytest.mark.parametrize("test_input,expected", [("3+5", 8), ("2+4", 6), ("6*9", 42)])
def test_eval(test_input, expected):
assert eval(test_input) == expected
Instrução @pytest.fixture
[editar | editar código]As fixtures são funções que criam um contexto confiável, consistente e bem definido para os testes, fornecendo dados ou estados necessários para a execução dos mesmos, o que permite que os testes sejam executados de forma isolada e controlada. Além disso, é muito útil para sinalizar quais funções devem ser executadas primeiro.
Os serviços, estado ou outros ambientes operacionais configurados por fixtures são acessados por funções de teste por meio de argumentos. Para cada fixture usada por uma função de teste, normalmente há um parâmetro (nomeado após o fixture) na definição da função de teste. Podemos sinalizar ao PyTest que uma função específica é um fixture utilizando @pytest.fixture. Confira o exemplo abaixo:
import pytest
class Fruit:
def __init__(self, name):
self.name = name
def __eq__(self, other):
return self.name == other.name
@pytest.fixture
def my_fruit():
return Fruit("apple")
@pytest.fixture
def fruit_basket(my_fruit):
return [Fruit("banana"), my_fruit]
def test_my_fruit_in_basket(my_fruit, fruit_basket):
assert my_fruit in fruit_basket
A partir do exemplo, temos o seguinte fluxo:
- O Pytest identifica as dependências do teste (
my_fruitefruit_basket) e executa as fixtures correspondentes para criar os objetos necessários. - A fixture
my_fruitretorna uma instância deFruitcom o nome"apple". - A fixture
fruit_basketcria uma lista contendo uma banana e a maçã (referenciada comomy_fruit). - O teste verifica se a instância retornada por
my_fruitestá na listafruit_basket. - O método
__eq__da classeFruité usado para comparar os objetos durante a execução doassert.
Após a execução do código, temos que o teste foi aprovado pois a ordem de execução ocorreu corretamente:
=================================================================== test session starts ===================================================================
platform win32 -- Python 3.9.5, pytest-8.3.3, pluggy-1.5.0
rootdir: /tutorial
collected 1 item
test_fruits.py . [100%]
==================================================================== 1 passed in 0.08s ====================================================================
Referências
[editar | editar código]DataCamp. Pytest Tutorial: A Hands-On Guide to Unit Testing. Disponível em: https://www.datacamp.com/pt/tutorial/pytest-tutorial-a-hands-on-guide-to-unit-testing. Acesso em: 29 nov. 2024.
IBM. Software Testing. Disponível em: https://www.ibm.com/br-pt/topics/software-testing. Acesso em: 29 nov. 2024.
MICROSOFT. Testando Python com o Pytest. Disponível em: https://learn.microsoft.com/pt-br/training/modules/test-python-with-pytest/. Acesso em: 29 nov. 2024.
PYTEST. Getting Started. Disponível em: https://docs.pytest.org/en/stable/getting-started.html. Acesso em: 28 nov. 2024.