Introdução
O Python oferece diversas opções para automação de testes, com os frameworks Unittest e Pytest sendo as mais populares. Enquanto o Unittest é uma biblioteca padrão do Python que permite extensibilidade e desenvolvimento personalizado, o Pytest ganha destaque por sua sintaxe mais concisa, flexibilidade e ecossistema de plugins rico. Este artigo explora as principais diferenças entre esses dois frameworks, ajudando você a escolher o mais adequado para seus projetos.
Comparação: Unittest vs Pytest
Vamos analisar as diferenças fundamentais entre esses frameworks em vários aspectos:
Regras de Escrita de Testes
Condições Pré e Pós-teste
Asserções
Relatórios de Teste
Mecanismo de Reexecução em Falhas
Parametrização
Execução Classificada de Testes
Para uma visão consolidada, apresentamos uma tabela comparativa:
| Característica | Unittest | Pytest |
|---|---|---|
| Complexidade de Código | Alta | Baixa |
| Compatibilidade | Limitada | Amplamente compatível |
| Plugins | Poucos disponíveis | Extensa variedade |
| Personalização | Fácil de estender | Extensível através de fixtures |
| Execução Paralela | Não suportada nativamente | Suportada via plugin xdist |
| Sintaxe | Mais verbosa | Concisa e expressiva |
Em resumo, o Unittest possui uma estrutura de código mais complexa, com compatibilidade limitada e poucos plugins, mas oferece facilidade para desenvolvimento personalizado. Por outro lado, o Pytest é mais conveniente e rápido, com sintaxe simplificada, capacidade de executra testes no estilo Unittest sem modificações, e excelente compatibilidade. O ecossistema de plugins do Pytest é significativamente mais rico, incluindo plugins para Flask, reexecução em falhas e execução paralela via xdist, resultando em maior eficiência.
Demonstração Prática
Para ilustrar as diferenças práticas entre esses frameworks, apresentaremos exemplos comparativos de implementação.
Diferenças em Configurações Pré e Pós-teste
Primeiro, vamos examinar como o Unittest lida com configurações de setup e teardown:
import unittest
class TestConfiguracoes01(unittest.TestCase):
# Executado antes de todos os testes
def setUp(self) -> None:
print("Início do setUp")
def tearDown(self) -> None:
print("Fim do tearDown")
# Executado uma vez por classe
@classmethod
def setUpClass(cls) -> None:
print("Início do setUpClass")
@classmethod
def tearDownClass(cls) -> None:
print("Fim do tearDownClass")
# Caso de teste
def teste_001(self):
print("Caso de teste 001")
class TestConfiguracoes02(unittest.TestCase):
def teste_002(self):
print("Classe de teste 2")
# Executado antes de todos os módulos
def setUpModulo():
"""
Executado uma vez antes de todas as classes de teste,
o nome da função é fixo e reconhecido automaticamente pelo Unittest
"""
print('Teste de integração >>>>>>>>>>>>>>Início')
def tearDownModulo():
print("Teste de integração >>>>>>>>>>>>>>Fim")
if __name__ == '__main__':
unittest.main()
Agora, vejamos como o Pytest lida com essas mesmas configurações:
- O Pytest oferece maior flexibilidade para configurações pré e pós-teste, permitindo definição personalizada através de fixtures. A hierarquia de execução é:
- Nível de módulo: Global, executado uma vez para todo o módulo, antes dos casos de teste.
- Nível de classe: Definido dentro da classe, aplicável apenas a essa classe.
- Nível de função: Aplicável apenas a funções fora de classes.
- Nível de método: Definido dentro de classes, executado para cada método.
def setup_modulo():
print('\nAntes de todo o módulo - executado uma vez')
def teardown_modulo():
print('\nDepois de todo o módulo - executado uma vez')
def setup_funcao():
print('\nAntes de cada função fora de classe')
def teardown_funcao():
print('\nDepois de cada função fora de classe')
def teste_ab():
valor = 2
assert valor < 3
def teste_aba():
valor = 2
assert valor < 3
class TestAPI():
def setup_classe(self):
print('\nAntes dos testes desta classe')
def teardown_classe(self):
print('\nDepois dos testes desta classe')
def setup_metodo(self):
print('\nAntes de cada método desta classe')
def teardown_metodo(self):
print('\nDepois de cada método desta classe')
def test_aa(self):
a = 1
print('\nCaso de teste: a')
assert a > 0
def test_b(self):
b = 2
assert b < 3
- Usando Fixtures no Pytest:
As fixtures no Pytest permitem definir configurações personalizadas. Primeiro, criamos um arquivo conftest.py:
# conftest.py
import pytest
@pytest.fixture
def login():
print("Realizando login...")
return "token_autenticacao"
Em seguida, usamos essa fixture nos nossos testes:
# arquivo_teste.py
def teste_um(login):
print("Após login, executando operação 111")
def teste_tres(login):
print("Após login, executando operação 333")
- Uso avançado com múltiplas fixtures:
# conftest.py
import pytest
@pytest.fixture
def login():
print("Realizando login...")
return "token_autenticacao"
@pytest.fixture
def abrir_pagina():
print("Abrindo página inicial...")
return "pagina_principal"
# arquivo_teste.py
def teste_um(login):
print("Após login, executando operação 111")
def teste_dois(login, abrir_pagina):
print("Executando teste 2 com login e página aberta")
def teste_tres(abrir_pagina):
print("Executando teste 3 apenas com página aberta")
Diferenças em Parametrização
A parametrização é útil quando precisamos testar múltiplos cenários com diferentes dados. Por exemplo, ao testar uma funcionalidade de login com combinações de usuário e senha válidos e inválidos.
Parametrização no Unittest:
O Unittest utiliza a biblioteca DDT (Data-Driven Tests) para parametrização:
dados_teste = [1, 2, 3]
@ddt.ddt
class TestParametrizado(unittest.TestCase):
@ddt.data(*dados_teste)
def teste_001(self, dado):
print(dado)
Parametrização no Pytest:
O Pytest possui suporte nativo para parametrização através do decorator @pytest.mark.parametrize:
@pytest.mark.parametrize('dado', [1, 2, 3])
class TestParametrizado(object):
def teste_001(self, dado):
print(dado)
Para parâmetros múltiplos:
@pytest.mark.parametrize("parametro1, parametro2", [
(1, 2),
(3, 4),
(5, 6)
])
def teste_multiparametro(parametro1, parametro2):
resultado = parametro1 + parametro2
assert resultado > 0
Conclusão
Os frameworks Unittest e Pytest oferecem abordagens distintas para automação de testes em Python. Enquanto o Unittest é mais estruturado e parte da biblioteca padrão, o Pytest proporciona maior flexibilidade, sintaxe mais concisa e um ecossistema de plugins mais rico. A escolha entre eles dependerá das necessidades específicas do seu projeto, equipe e perferências de desenvolvimento.