O test runner embutido do Django funciona, mas o pytest deixa os testes mais poderosos. Mensagens de erro melhores, parametrize para testes orientados a tabela, e um ecossistema maior de plugins para cobertura, factories e acesso ao banco.
TL;DR: Configure o pytest-django para rodar o seu test suite Django, adicione fixtures, use factories para dados de teste e obtenha relatórios de cobertura.
Stack: Python, Django, pytest, pytest-django, factory-boy
Nível: Intermediário
Tempo de leitura: ~9 min
Configurar projeto Django com DRF
pip install django djangorestframework
django-admin startproject projtest .
python3 manage.py startapp app
Criar o model Hero
class Hero(models.Model):
name = models.CharField(max_length=100)
canFly = models.BooleanField()
genre = models.CharField(max_length=10)
Criar caso de uso, protocolos e controller
Organize o projeto em camadas: application/use_cases/, infra/, main/ e presentation/. O controller delega para o caso de uso, e o caso de uso fica livre de preocupações HTTP.
class ListHeroesController(APIView):
def post(self, request):
try:
inbound = ListHeroesRequest()
inbound.canFly = request.data.get("canFly", "false").lower() == "true"
inbound.genre = request.data.get("genre", "male")
use_case = ListHeroes()
result = use_case.execute(inbound)
outbound = [hero.__dict__ for hero in result]
return Response({"data": outbound}, status=status.HTTP_200_OK)
except Exception as e:
return Response({"message_error": str(e)}, status=status.HTTP_500_INTERNAL_SERVER_ERROR)
Instalar pytest
pip install pytest pytest-django
Criar pytest.ini
[pytest]
DJANGO_SETTINGS_MODULE = projtest.settings
python_files = tests.py test_*.py *_tests.py
Escrever testes
# tests/unit/test_list_heroes.py
import pytest
from application.use_cases.list_heroes.list_heroes import ListHeroes
from application.use_cases.list_heroes.protocols.list_heroes_request import ListHeroesRequest
from app.models import Hero
@pytest.mark.django_db
def test_list_heroes_use_case():
Hero.objects.create(name="Superman", canFly=True, genre="male")
Hero.objects.create(name="Wonder Woman", canFly=False, genre="female")
Hero.objects.create(name="Batman", canFly=False, genre="male")
inbound = ListHeroesRequest()
inbound.canFly = True
inbound.genre = "male"
use_case = ListHeroes()
result = use_case.execute(inbound)
assert len(result) == 1
assert result[0].name == "Superman"
assert result[0].canFly is True
pytest
Adicionar cobertura
pip install pytest-cov
pytest --cov=application --cov-report=term-missing
Crie .coveragerc para excluir arquivos de protocolo da cobertura (são containers de dados, não lógica):
[run]
omit =
application/use_cases/*/protocols/*
O que você construiu
O pytest configurado para o seu projeto Django com testes funcionando, fixtures de banco de dados e relatório de cobertura.
Próximos passos
- Use @pytest.mark.django_db nos testes que precisam de acesso ao banco. Sem isso, chamadas ao banco levantam um erro.
- Use factory-boy para dados de teste: UserFactory() é mais limpo do que repetir o setup do model em cada teste.
- Rode pytest –reuse-db com pytest-django para pular as migrations em execuções repetidas dos testes, o que acelera bastante o suite.
Dúvidas ou feedback? Me encontre no LinkedIn ou GitHub.