Testes Avançados em Python: unittest, pytest e Mocks Complexos
1. Fundamentos de Testes
Testes Unitários: verificam funcionalidades isoladas de funções ou classes.
Testes de Integração: verificam como múltiplos componentes interagem.
Mocks: substituem dependências externas para testar unidades isoladas.
Python oferece módulos nativos (unittest
, unittest.mock
) e frameworks avançados como pytest.
2. unittest Avançado
2.1 Estrutura Básica
import unittest
class TestMath(unittest.TestCase):
def test_soma(self):
self.assertEqual(2 + 2, 4)
Herda
unittest.TestCase
.Usa métodos
assertEqual
,assertTrue
,assertRaises
, etc.
2.2 Fixtures e Setup/Teardown
class TestDB(unittest.TestCase):
def setUp(self):
self.db = criar_conexao_mock()
def tearDown(self):
self.db.fechar()
def test_query(self):
resultado = self.db.consultar("SELECT 1")
self.assertEqual(resultado, 1)
setUp
executa antes de cada testetearDown
limpa recursos após o teste
2.3 Subtests
Permite rodar vários cenários dentro do mesmo teste:
def test_multiplos_valores(self):
for valor in range(5):
with self.subTest(valor=valor):
self.assertLess(valor, 5)
Facilita identificação de falhas por caso específico.
3. pytest Avançado
3.1 Sintaxe Simples
def soma(a, b):
return a + b
def test_soma():
assert soma(2, 3) == 5
pytest permite asserts nativos, sem precisar de
TestCase
.
3.2 Parametrização
import pytest
@pytest.mark.parametrize("a,b,resultado", [(2,3,5),(0,0,0),(-1,1,0)])
def test_soma_param(a,b,resultado):
assert a + b == resultado
Permite testar múltiplos cenários automaticamente.
3.3 Fixtures Avançadas
import pytest
@pytest.fixture(scope="module")
def db():
conexao = criar_conexao_mock()
yield conexao
conexao.fechar()
def test_query(db):
resultado = db.consultar("SELECT 1")
assert resultado == 1
scope
define duração da fixture (function
,module
,session
)yield
permite setup/teardown avançado
4. Mocks Complexos
4.1 Mocking de Funções e Objetos
from unittest.mock import patch
@patch("modulo.database.query")
def test_query_mock(mock_query):
mock_query.return_value = 42
from modulo import database
resultado = database.query("SELECT 1")
assert resultado == 42
Substitui função real por mock configurável.
4.2 Side Effects
Para simular retornos diferentes em chamadas sequenciais ou exceções:
mock_query.side_effect = [1, 2, Exception("Erro simulado")]
Útil para testes de falhas e retries.
4.3 Mock de Context Managers
from unittest.mock import MagicMock, patch
mock_file = MagicMock()
mock_file.__enter__.return_value.read.return_value = "conteúdo"
with patch("builtins.open", return_value=mock_file):
with open("arquivo.txt") as f:
conteudo = f.read()
assert conteudo == "conteúdo"
Permite simular arquivos, conexões e recursos com
with
.
4.4 Mock de Classes Inteiras
with patch("modulo.ClasseExterna") as MockClass:
MockClass.return_value.metodo.return_value = 10
Útil para dependências externas ou caras de inicializar.
5. Testes Assíncronos
pytest suporta asyncio com
pytest-asyncio
:
import pytest
import asyncio
async def async_soma(a,b):
await asyncio.sleep(0.1)
return a+b
@pytest.mark.asyncio
async def test_async_soma():
resultado = await async_soma(2,3)
assert resultado == 5
Fundamental para APIs assíncronas e I/O não bloqueante.
6. Boas Práticas Profissionais
Organize testes em módulos e pacotes separados (
tests/
).Use pytest para simplicidade, parametrização e fixtures.
Use mocks e side effects para isolar testes e simular falhas.
Combine unittest e pytest quando necessário para compatibilidade.
Escreva testes assíncronos para sistemas async.
Integre com CI/CD para execução automática em cada commit.
Sempre limpe recursos externos em fixtures ou teardown.
7. Aplicações Profissionais
APIs web (Flask, FastAPI)
Serviços assíncronos (asyncio, aiohttp)
Integração com bancos de dados e serviços externos
Sistemas críticos de produção que exigem testes confiáveis
8. Conclusão
Testes avançados garantem qualidade, confiabilidade e manutenção.
Técnicas incluem:
unittest com setup/teardown e subtests
pytest com fixtures, parametrização e async
Mocks complexos com side_effects, context managers e classes inteiras
Seguindo boas práticas, é possível criar pipelines de teste robustos e escaláveis, essenciais em produção.
Comentários
Postar um comentário