Por que testes automatizados falham em detectar mudanças na API e como corrigir com Pydantic

Por que testes automatizados falham em detectar mudanças na API e como corrigir com Pydantic

Descubra como testes automatizados de API podem falhar em identificar alterações e como a biblioteca Pydantic pode ser a solução para garantir a robustez e a precisão das suas validações.

MundiX News·02 de maio de 2026·9 min de leitura·👁 8 views

Olá, Habr!

Meu nome é Vladislav Timashenkov, e eu trabalho com automação de testes na GK Infowatch. Nossa equipe se deparou com problemas comuns em testes automatizados para APIs: uma única alteração na API exige a atualização de vários testes; a verificação da estrutura da resposta está distribuída entre os testes e não centralizada; e a validação de estruturas aninhadas e campos gerados requer código adicional. Diante disso, nos perguntamos: qual ferramenta de validação de contrato seria adequada para nós? Neste artigo, compartilharemos nossa reavaliação da abordagem de teste de API através da implementação do Pydantic.

Vamos considerar um exemplo simples de teste para criação de um usuário:

python
# ../your_project/tests/user/test_crud_user.py

def test_create_user():
    user_creation_body = {
        "USERNAME": "John_Smith",
        "EMAIL": "john@example.com",
        "DISPLAY_NAME": "John Smith",
    }
    response = requests.post(f"{SOME_URL}/user", json=user_creation_body)
    response.raise_for_status()
    data = response.json()
    assert data["USERNAME"] == user_creation_body["USERNAME"]
    assert data["EMAIL"] == user_creation_body["EMAIL"]
    assert data["DISPLAY_NAME"] == user_creation_body["DISPLAY_NAME"]
    assert isinstance(data["USER_ID"], int)

Este teste verifica o sucesso da execução da requisição e a conformidade dos dados em campos específicos. No entanto, essa abordagem apresenta várias desvantagens:

  • Não há verificação de toda a estrutura de dados da resposta.
  • Não há uma descrição unificada do contrato.
  • Duplicação de assert (a validação de tipo para data["USER_ID"] é necessária em todos os testes que envolvem a entidade USER).
  • Alterações na API podem passar despercebidas em campos não verificados.

Por isso, decidimos isolar o contrato da API em uma camada de validação separada. Para isso, precisamos de uma ferramenta que:

  • Valide a estrutura com base em um contrato unificado.
  • Seja implementada de forma independente.
  • Falhe em caso de divergência com a API.
  • Seja implementada e escalada gradualmente.

Inicialmente, tentamos usar templates e descrever as respostas como JSON de referência para comparar a estrutura e o valor da resposta com um template pré-definido. Isso atendia parcialmente às necessidades de estrutura de dados, mas oferecia poucas possibilidades de validação de campos e escalabilidade.

O Pydantic v2 resolve essas tarefas através de tipagem estrita, validação integrada e comportamento previsível, tornando-o a melhor opção para nossos requisitos. Uma requisição do teste no exemplo anterior:

python
requests.post(f"{SOME_URL}/user", json=user_creation_body).json()

Retornará o seguinte JSON:

json
{
 "USER_ID": 69,
 "USERNAME": "John_Smith",
 "DISPLAY_NAME": "John Smith",
 "EMAIL": "john@example.com",
 "NOTE": null,
 "CREATE_DATE": "2026-01-01T00:01:30.897869",
 "STATUS": 1
}

Com base na documentação da API do projeto, podemos conhecer os requisitos para os valores dos campos. Criaremos um modelo Pydantic para o corpo da resposta com base nisso. O modelo descreve as estruturas de dados usando anotações de tipo do Python. Ele define quais campos são esperados na resposta, seus tipos e restrições, e também valida automaticamente os dados ao criar um objeto. Cada campo é um atributo do modelo com uma chamada conveniente.

python
# ../your_project/models/user/response.py

from datetime import datetime
from enum import IntEnum
from pydantic import BaseModel, ConfigDict, EmailStr, Field, PositiveInt

class UserStatuses(IntEnum):
    active = 1
    inactive = 0

class UserResponseModel(BaseModel):
    # Configuramos o modelo: definimos regras de validação e processamento de campos.
    model_config = ConfigDict(
        extra="forbid",  # Proíbe novos campos na resposta da API.
        populate_by_name=True,  # Permite usar tanto aliases de campos quanto seus nomes.
        alias_generator=lambda field_name: field_name.upper()  # Gera alias (UPPER_CASE) para corresponder ao formato dos campos no modelo e na API.
    )

    # Apenas números positivos são permitidos
    user_id: PositiveInt

    # String com comprimento entre 8 e 32 caracteres
    username: str = Field(min_length=8, max_length=32)
    display_name: str = Field(min_length=8, max_length=32)

    # Formato de email válido. Por baixo dos panos, usa EmailStr ou email-validator.
    email: EmailStr

    # Campo opcional.
    note: str | None = None

    # Data e hora no formato datetime.
    create_date: datetime

    # Valor do enum UserStatuses
    status: UserStatuses

Agora, o projeto possui um módulo com a descrição do contrato para a criação de usuários. Ele responde à pergunta: "Como deve ser a resposta?". Essencialmente, é uma documentação executável para a API, uma descrição do contrato do lado do cliente.

O teste atualizado verifica a estrutura através do modelo Pydantic, e os asserts são responsáveis apenas pela lógica de negócio.

python
# ../your_project/tests/user/test_crud_user.py

from ..models.user.response import UserResponseModel

def test_create_user():
    user_creation_body = {
        "USERNAME": "John_Smith",
        "EMAIL": "john@example.com",
        "DISPLAY_NAME": "John Smith",
    }
    response = requests.post(f"{SOME_URL}/user", json=user_creation_body)
    response.raise_for_status()
    data = response.json()

    user_model = UserResponseModel.model_validate(data)
    
    # Campos do corpo da resposta - atributos do modelo Pydantic
    assert user_model.USERNAME == user_creation_body["USERNAME"]
    assert user_model.EMAIL == user_creation_body["EMAIL"]
    assert user_model.DISPLAY_NAME == user_creation_body["DISPLAY_NAME"]

Agora, se o campo "CREATE_DATE" retornar o valor "31-03-2026" e um novo campo "IS_BLOCKED": false for adicionado, o teste falhará, mesmo que não haja asserts para esses campos. Para ilustrar, vejamos a exceção bruta ValidationError:

pydantic_core._pydantic_core.ValidationError: 2 validation errors for UserResponseModel

CREATE_DATE
  Input should be a valid datetime or date, invalid character in year [type=datetime_from_date_parsing, input_value='31-03-2026', input_type=str]
    For further information visit https://errors.pydantic.dev/2.11/v/datetime_from_date_parsing

IS_BLOCKED
  Extra inputs are not permitted [type=extra_forbidden, input_value=False, input_type=bool]
    For further information visit https://errors.pydantic.dev/2.11/v/extra_forbidden

Quanto mais modelos, mais fácil se torna adicionar novos testes. Como os modelos são abstraídos em uma camada separada, eles podem ser reutilizados em outros modelos, estendendo seu contrato, muitas vezes sem a necessidade de escrever novo código. Por exemplo, NotificationModel utiliza os modelos UserResponseModel e TemplateModel já prontos:

python
# ../your_project/models/notifications/response.py

from datetime import datetime

from ..models.user.response import UserResponseModel
from ..models.templates.response import TemplateResponseModel

from pydantic import BaseModel, ConfigDict

class NotificationResponseModel(BaseModel):
    model_config = ConfigDict(
        extra="forbid",
        populate_by_name=True,
        alias_generator=lambda field_name: field_name.upper()
    )
    
    notification_id: str
    display_name: str
    create_date: datetime
    # Validações recursivas automáticas para cada item da lista
    recipients: list[UserResponseModel]
    templates: list[TemplateResponseModel]

E UserResponseModel participa tanto da criação de NotificationResponseModel quanto do teste test_add_notification sem duplicação de código. Qualquer alteração no modelo Pydantic é automaticamente aplicada a todos os testes e modelos que o utilizam.

python
# ../your_project/tests/notification/test_add_notification.py

from ..models.notifications.response import NotificationResponseModel

def test_add_notification():
    notification_add_body = {
        "DISPLAY_NAME": "John Smith",
        "RECIPIENTS": [..],
        "TEMPLATES": [..],
    }
    response = requests.post(f"{SOME_URL}/notification", json=notification_add_body)
    data = response.json()
    notification_model = NotificationResponseModel.model_validate(data)
    assert notification_model.DISPLAY_NAME == notification_add_body["DISPLAY_NAME"]

Nossa experiência com a implementação da abordagem Pydantic:

Desmembramos o épico em tarefas e implementamos gradualmente o suporte ao Pydantic no framework do projeto, descrevemos os endpoints mais importantes para entidades complexas, adicionamos modelos conforme as alterações nos testes existentes e extraímos estruturas repetitivas para modelos comuns. Não foi necessário reescrever tudo de uma vez; um endpoint requer aproximadamente 1 a 3 modelos, dependendo da estrutura. Uma excelente ferramenta para acelerar a geração de modelos foi o datamodel-code-generator. A partir da especificação OpenAPI, ele gera modelos em uma única chamada, que podem então ser adaptados ao estilo do projeto e complementados com validação. Exemplo:

bash
datamodel-codegen \
  --input your_openapi_spec.yaml \
      # caminho para a especificação OpenAPI de origem
  --input-file-type openapi \
      # especificamos o tipo da especificação
  --output your_path/ \
      # caminho para a geração dos modelos
  --target-python-version 3.13 \
      # versão do Python para usar sintaxe atual
  --output-model-type pydantic_v2.BaseModel \
      # usar Pydantic v2 BaseModel como classe base dos modelos
  --snake-case-field \
      # converter nomes de campos para snake_case
  --use-double-quotes \
      # usar aspas duplas no código gerado
  --use-schema-description \
      # transferir a descrição do schema para docstring ou Field(description=...)
  --formatters ruff-check ruff-format      # verificar o código via Ruff (linters + autoformatação)

Em aproximadamente seis meses, conseguimos escrever mais de 280 modelos que cobriram mais de 1740 campos e grande parte do contrato. Um valioso efeito colateral foi que revisamos a API do produto e descobrimos uma série de problemas não óbvios e anteriormente não detectados: tipos incompatíveis, valores inesperados, campos e lógicas ausentes na documentação.

Como resultado, mudamos a própria abordagem de teste de API do produto principal da InfoWatch:

  • As verificações são divididas em duas camadas independentes: validação da estrutura da resposta e validação da lógica de negócio.
  • Monitoramos as alterações na API de forma automática e centralizada.
  • Reduzimos o número de asserts nos testes, transferindo as verificações de estrutura para os modelos.
  • Aumentamos a cobertura através da reutilização de modelos.

Essa abordagem escala particularmente bem em projetos grandes onde a API está em constante desenvolvimento.

🛡️⚡

Pare de pesquisar. Comece a hackear.

O MundiX é seu copiloto de pentest com IA: comandos exatos, análise de outputs e próximo passo na kill chain — em segundos.

Testar grátis por 7 dias →

Sem cartão para começar · Planos a partir de R$49/mês

📤 Compartilhar & Baixar

🧰 Ferramentas recomendadas

Divulgação: alguns links são patrocinados. Podemos receber comissão se você comprar — sem custo extra para você. Só indicamos o que faz sentido para a comunidade.

Aprendendo Kali Linux: Teste de segurança, pentest e hacking ético

Aprendendo Kali Linux: Teste de segurança, pentest e hacking ético

Com centenas de ferramentas pré-instaladas, a distribuição Kali Linux facilita o trabalho de os profissionais de segurança começarem a fazer testes de segurança rapidamente. No entanto, com mais de 600 ferramentas em seu arsenal, o Kali Linux também pode ser desafiador. A nova edição deste prático livro abrange as atualizações nas ferramentas e inclui uma melhor abordagem da análise forense e da engenharia reversa. Ric Messier, autor, não fica apenas no teste de segurança, mas também faz uma abordagem sobre a execução de análise forense, incluindo a análise em disco e na memória, assim como alguma análise básica de malware. • Explore as diversas ferramentas disponíveis no Kali Linux • Entenda o valor do teste de segurança e examine os tipos de teste disponíveis • Aprenda os aspectos básicos do pentest em todo o ciclo de vida do ataque • Instale o Kali Linux em vários sistemas, tanto físicos quanto virtuais • Descubra como usar diferentes ferramentas destinadas à segurança • Estruture um teste de segurança baseado nas ferramentas do Kali Linux • Estenda as ferramentas do Kali para criar técnicas de ataque avançadas • Use o Kali Linux para ajudar a criar relatórios quando o teste terminar “A abordagem concisa, clara e baseada na experiência adotada por Ric Messier para a introdução do Kali Linux e dos testes de cibersegurança é incomparável. Este livro é uma leitura excelente e acessível para iniciantes e um recurso valioso para qualquer pessoa.” —Alexander Arlt, Consultor sênior de segurança, Google

Ver na Amazon
Gshield 2 em 1 Hub Extensor Conector USB-C + USB-A e Adaptador de Rede Ethernet LAN RJ45 com 3 Entradas USB 3.0 até 5 Gbps em Liga de Alumínio para Computador e Notebook, Cinza

Gshield 2 em 1 Hub Extensor Conector USB-C + USB-A e Adaptador de Rede Ethernet LAN RJ45 com 3 Entradas USB 3.0 até 5 Gbps em Liga de Alumínio para Computador e Notebook, Cinza

Compatível com portas USB-C e USB-A, ideal para ampliar a conectividade de dispositivos como MacBook Pro e outros com portas USB-C. Inclui um adaptador USB-A extra, proporcionando uma conexão Ethernet estável e veloz de até 1 Gbps, perfeita para filmes, jogos online e videoconferências. Oferece três portas USB 3.0 com velocidades de transferência de até 5 Gbps, permitindo conectar mouse, teclado, discos rígidos e outros periféricos. Fabricado em alumínio durável, garantindo longa vida útil e resistência ao uso diário. Design compacto e leve, ideal para viagens de negócios e uso diário, facilitando o transporte e armazenamento. Funciona com Windows 10/8.1/8, Mac OS e Chrome OS, oferecendo versatilidade incomparável para diversas necessidades de conectividade. Assegura uma conectividade estável e rápida, perfeita para tarefas exigentes como transferência de dados, streaming e mais.

Ver na Amazon
Hacking APIs: Breaking Web Application Programming Interfaces

Hacking APIs: Breaking Web Application Programming Interfaces

Hacking APIs is a crash course on web API security testing that will prepare you to penetration-test APIs, reap high rewards on bug bounty programs, and make your own APIs more secure. You'll learn how REST and GraphQL APIs work in the wild and set up a streamlined API testing lab with Burp Suite and Postman. Then you'll master tools useful for reconnaissance, endpoint analysis, and fuzzing, such as Kiterunner and OWASP Amass. Next, you'll learn to perform common attacks, like those targeting an API's authentication mechanisms and the injection vulnerabilities commonly found in web applications. You'll also learn techniques for bypassing protections against these attacks. In the book's nine guided labs, which target intentionally vulnerable APIs, you'll practice: Enumerating APIs users and endpoints using fuzzing techniques Using Postman to discover an excessive data exposure vulnerability Performing a JSON Web Token attack against an API authentication process Combining multiple API attack techniques to perform a NoSQL injection Attacking a GraphQL API to uncover a broken object level authorization vulnerability

Ver oferta
Gray Hat Hacking: The Ethical Hacker's Handbook, Sixth Edition

Gray Hat Hacking: The Ethical Hacker's Handbook, Sixth Edition

Up-to-date strategies for thwarting the latest, most insidious network attacks This fully updated, industry-standard security resource shows, step by step, how to fortify computer networks by learning and applying effective ethical hacking techniques. Based on curricula developed by the authors at major security conferences and colleges, the book features actionable planning and analysis methods as well as practical steps for identifying and combating both targeted and opportunistic attacks. Gray Hat Hacking: The Ethical Hacker's Handbook, Sixth Edition clearly explains the enemy's devious weapons, skills, and tactics and offers field-tested remedies, case studies, and testing labs. You will get complete coverage of Internet of Things, mobile, and Cloud security along with penetration testing, malware analysis, and reverse engineering techniques. State-of-the-art malware, ransomware, and system exploits are thoroughly explained. Fully revised content includes 7 new chapters covering the latest threats Includes proof-of-concept code stored on the GitHub repository Authors train attendees at major security conferences, including RSA, Black Hat, Defcon, and B-Sides

Ver na Amazon
Bloqueador USB de privacidade de porta USB para PC, notebook, bloco de laptop,

Bloqueador USB de privacidade de porta USB para PC, notebook, bloco de laptop,

Proteção de privacidade aprimorada: protege o link de transmissão de dados para evitar roubo de informações, fornecendo proteção de segurança robusta que protege a privacidade do usuário durante transferências de arquivos e garante uma conexão segura para interações de dispositivos sem preocupações em vários ambientes Uso a longo prazo: a camada protetora resistente ao desgaste, combinada com um corpo de metal resistente, oferece gerenciamento de calor confiável e qualidade duradoura durante o uso diário Entrega eficiente de energia: a tecnologia de chip inteligente garante a identificação automática dos requisitos de energia, fornecendo carregamento eficiente alinhando-se com vários protocolos de carregamento rápido para maior conveniência Proteção contra sobrecarga: evitando riscos de sobrecarga, este bloqueador de dados USB protege a vida útil da bateria e garante um desempenho estável, mantendo um fluxo estável de energia para melhorar a longevidade do dispositivo de forma eficaz Prático de transportar: com atenção à portabilidade, este bloqueador de dados USB oferece um design compacto que é leve e fácil de transportar, melhorando a conveniência do usuário e operação eficiente

Ver na Amazon

📩 Newsletter MundiX

Receba novidades de cibersegurança + um checklist de pentest grátis. Sem spam.

Ao assinar você concorda em receber e-mails. Cancele quando quiser.