Skip to content

Resolução Desafio Desenvolvendo sua Primeira API com FastAPI, Python e Docker#25

Open
Luiz0tavi0 wants to merge 15 commits intodigitalinnovationone:mainfrom
Luiz0tavi0:main
Open

Resolução Desafio Desenvolvendo sua Primeira API com FastAPI, Python e Docker#25
Luiz0tavi0 wants to merge 15 commits intodigitalinnovationone:mainfrom
Luiz0tavi0:main

Conversation

@Luiz0tavi0
Copy link

Workout API - Fork com Melhorias

Python
FastAPI
License: MIT
Tests
Coverage

Este fork do repositório original digitalinnovationone/workout_api traz atualizações e melhorias com foco em qualidade de código, ferramentas modernas e testes robustos.

🔧 Atualização de Dependências

  • Atualizado para Python 3.13
  • FastAPI atualizado para ^0.116.1
  • SQLAlchemy v2 com suporte a asyncio
  • Substituição do psycopg2 por psycopg[binary] (versão 3)
  • Atualização para pydantic-settings v2

⚙️ Gerenciamento com Poetry

  • Uso do Poetry para gerenciamento de dependências com pyproject.toml
  • Separação entre dependências de produção e desenvolvimento

🧪 Testes Modernos

  • Testes assíncronos com pytest-asyncio
  • Cobertura de código com pytest-cov
  • Testes com banco real usando testcontainers
  • Geração de dados com factory-boy
  • Parametrização de testes com @pytest.mark.parametrize

🐳 Testes com TestContainers

🧪 Testes Automatizados com Banco Real (TestContainers + SQLAlchemy Async)

Este projeto utiliza um setup moderno e robusto para testes, com as seguintes características:

  • Banco de Dados real com TestContainers: Usa um container Docker do PostgreSQL durante os testes.
  • Integração assíncrona completa com SQLAlchemy Async e httpx.AsyncClient.
  • Factories com factory_boy para gerar dados consistentes nos testes.
  • Criação e teardown automáticos das tabelas a cada teste.

Exemplo de como o banco é iniciado e utilizado nos testes:

from testcontainers.postgres import PostgresContainer
from sqlalchemy.ext.asyncio import create_async_engine

@pytest.fixture(scope='session')
def engine():
    with PostgresContainer('postgres:17', driver='psycopg') as postgres:
        database_url = postgres.get_connection_url()
        _engine = create_async_engine(database_url)
        yield _engine

Além disso, o client de testes substitui a dependência original de get_session para injeção direta da AsyncSession, mantendo os testes isolados e controlados.

@pytest_asyncio.fixture
async def client(session: AsyncSession) -> AsyncGenerator[httpx.AsyncClient, None]:
    async def get_session_override():
        yield session

    app.dependency_overrides[get_session] = get_session_override
    # ...

Isso garante testes confiáveis, rápidos e que simulam o ambiente real da aplicação.

  • Utilização da biblioteca testcontainers para subir containers reais do PostgreSQL durante os testes.
  • Elimina a necessidade de banco local ou fixtures manuais.
  • Aumenta a confiabilidade dos testes ao simular um ambiente mais próximo do real.

Exemplo de uso:

from testcontainers.postgres import PostgresContainer

with PostgresContainer("postgres:17") as postgres:
    engine = create_async_engine(postgres.get_connection_url())
    # ...

🧹 Lint e Format com Ruff

  • Linting e formatação unificados com ruff
  • Configuração rígida: PEP8, PyLint e Pyflakes ativados
  • Uso de aspas simples e limite de 79 colunas
  • Diretórios como migrations/ excluídos do lint

🛠️ Automatização com Taskipy

  • Scripts prontos para facilitar o desenvolvimento:

    task lint       # Roda o linter com Ruff
    task format     # Formata o código
    task run        # Inicia o servidor FastAPI com hot reload
    task test       # Roda os testes com cobertura
  • Hooks automatizados:

    • pre_test: roda o lint antes dos testes
    • post_test: gera relatório HTML de cobertura após os testes

📁 Estrutura Moderna e Organizada

  • Separação clara por responsabilidades:
    • models/, schemas/, repositories/, routers/, exceptions/
  • Diretório tests/ com cobertura robusta e testes assíncronos
  • Configuração do pytest.ini com:
    • asyncio_mode = strict
    • pythonpath = "."
    • testpaths = ["tests"]

▶️ Como Executar

# Instalar dependências
poetry install

# Ativar ambiente virtual
poetry shell

# Rodar app com reload
task run

# Rodar testes com cobertura
task test

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant