Nossa Stack Tecnológica & Processo de Testes
O projeto Testando com Spring é uma recriação profunda, moderna e pedagógica em língua portuguesa do aclamado curso Test With Spring (© Koodikupla Oy). O objetivo fundamental desta iniciativa é libertar o desenvolvedor de práticas e ferramentas defasadas (como Java 8 legados, Spock com Groovy não tipado, Selenium flutuante e bancos em memória H2 artificiais), apresentando o estado da arte do ecossistema JVM moderno.
Nesta aula detalhamos a stack das aplicações sob teste ensinada ao longo das aulas e apresentamos um guia prático de engenharia passo a passo demonstrando como construímos a suíte de testes automatizados do próprio site utilizando a biblioteca padrão unittest do Python integrada ao Playwright e ao servidor Hugo via Devbox.
1. Nossa Stack Tecnológica
Todo o código, arquitetura e convenções abordados no curso utilizam estritamente versões de ponta e recursos contemporâneos parametrizados de forma centralizada:
| Tecnologia | Versão de Referência | Gerenciamento / Comando | Propósito na Arquitetura |
|---|---|---|---|
| Java JDK | 21 ou 25 (LTS) |
sdk install java 21.0.6-tem |
Runtime e compilador moderno da plataforma JVM gerenciado via SDKMAN. |
| Kotlin | 2.4.21+ |
sdk install kotlin 2.4.21 |
Linguagem concisa com suporte nativo a null safety, imutabilidade e corrotinas. |
| Spring Boot | 4.1.2+ |
curl https://start.spring.io/starter.zip ... |
Framework base para microsserviços, injeção de dependências e APIs web. |
| Gradle | 9.8.2+ (Kotlin DSL) |
sdk install gradle 9.8.2 |
Motor de compilação modular, rápido e configurado via build.gradle.kts. |
| JUnit Jupiter | 6.0.3+ |
testImplementation(libs.junit.jupiter) |
Motor moderno da arquitetura JUnit Platform para testes unitários na JVM. |
| Kotest | 6.2.6+ |
testImplementation(libs.kotest.runner.junit5) |
Framework BDD idiomático em Kotlin com DescribeSpec e matchers expressivos. |
| AssertJ Core | 3.27.7+ |
testImplementation(libs.assertj.core) |
Biblioteca de asserções fluentes com ricas mensagens diagnósticas. |
| MockK | 1.14.0+ |
testImplementation(libs.mockk) |
Biblioteca de mocks e stubs de primeira classe para Kotlin. |
| Testcontainers | 2.0.5+ |
testImplementation(libs.testcontainers.postgresql) |
Containers reais efêmeros (PostgreSQL) para testes de integração confiáveis. |
| Playwright | 1.50.0+ |
testImplementation(libs.playwright) |
Automação e crawling End-to-End resiliente para Chromium, Firefox e WebKit. |
| Hugo | 0.169.0 |
devbox run -- hugo |
Gerador estático do portal educacional e documentação de aula. |
2. A Pirâmide e Filosofia de Testes
Ao longo das lições, seguimos uma disciplina pragmática de engenharia de software:
Playwright + Testcontainers
Validação do fluxo real de ponta a ponta"] IT["Testes de Integração
Spring Boot + PostgreSQL Real (@ServiceConnection)
Persistência, Repositórios, Segurança e Controllers"] UT["Testes Unitários Rápidos
JUnit Jupiter / Kotest + MockK + AssertJ
Lógica de domínio, regras isoladas e execução em milissegundos"] E2E --> IT IT --> UT
Princípios Norteadores:
- Confiança Real: Não usamos bancos de dados em memória (como H2 ou HSQLDB) para validar queries PostgreSQL; testamos sempre contra o PostgreSQL real via Testcontainers.
- Isolamento e Determinismo: Cada teste gerencia explicitamente suas fixtures ou reseta suas sequências e tabelas, garantindo que a ordem de execução nunca altere o resultado.
- DSL Limpa & Idiomática: O código de teste deve servir como a documentação executável mais legível e agradável do sistema.
3. Nosso Processo de Testes: Guia Passo a Passo da Suíte E2E
Não basta apenas ensinar boas práticas: nós aplicamos engenharia de testes rigorosa no ciclo de vida desta própria plataforma de ensino.
Abaixo, apresentamos a evolução cronológica e arquitetural da nossa suíte de testes End-to-End, desde a concepção inicial até a automação completa com o framework padrão unittest do Python e o Playwright.
(Mapa de Links)"] --> P2["3.2 Ambiente
(Devbox + UV)"] P2 --> P3["3.3 Subindo Hugo & Métricas
(setUpClass)"] P3 --> P4["3.4 Teste de Métricas
(Pages & Aliases)"] P4 --> P5["3.5 Playwright Crawler
(Exaustão do Mapa)"]
3.1 Resumo do Que Vamos Construir
Nosso objetivo é garantir que nenhuma das 158 lições, links de barra lateral, botões Anterior/Próximo ou referências cruzadas quebrem (HTTP 404/500).
Para isso, modelamos o teste em torno de uma estrutura de dados de Grafo com Mapa de Descoberta:
- Criamos um dicionário
links_map: Dict[str, bool]onde a chave é a URL normalizada e o valor booleano indica se ela já foi visitada (True) ou se acabou de ser descoberta e está pendente (False). - O teste inicia com as páginas fundamentais no mapa (ex.:
/,/packages/,/support/). - O navegador carrega cada URL pendente, inspeciona o DOM, encontra todos os links
<a>internos e adiciona os inéditos comoFalse. - O loop de teste só termina quando 100% dos links descobertos forem navegados com sucesso.
- Além disso, interceptamos a saída tabular de compilação do Hugo para validar a integridade das métricas do build (
Pages,Aliases,Static files). - Ao final, as asserções do
unittestvalidam:self.assertGreaterEqual(hugo_metrics["Pages"], 230)(mínimo de páginas esperadas).self.assertGreaterEqual(hugo_metrics["Aliases"], 200)(todos os aliases gerados).self.assertEqual(len(errors), 0)(zero links com erro).self.assertEqual(total_visitados, total_descobertos)(garantia de exaustão completa).
3.2 Ferramentas e Configuração do Ambiente
Adotamos ferramentas reproduzíveis que eliminam a clássica frase “funciona na minha máquina”:
- Devbox (Nix): Fornece o binário isolado do Hugo (
v0.166+) sem exigir instalação global no sistema operacional. - UV (Astral): O instalador e executor ultraveloz do ecossistema Python. Com
uv run --with playwright, o Playwright e suas dependências são baixados e executados em milissegundos sem poluir o ambiente do desenvolvedor. - Python
unittest: A biblioteca padrão do Python, dispensando dependências externas adicionais para o test runner.
Comando para rodar a suíte completa:
|
|
3.3 Passo 1: Capturando Métricas do Hugo e Ciclo de Vida (setUpClass e tearDownClass)
Durante o build do Hugo, o compilador gera no console uma tabela com a volumetria da geração:
|
|
No método @classmethod setUpClass, nós executamos o build estático preliminar, capturamos o stdout/stderr do processo e extraímos esses valores via expressão regular (re.search) para um dicionário Python reutilizável em todos os métodos de teste:
|
|
3.4 Passo 2: Asserções Sobre as Métricas de Build do Hugo
Agora que as métricas foram extraídas com sucesso, criamos o primeiro teste formal do unittest:
|
|
3.5 Passo 3: O Crawler Completo com Mapa de Links e Asserções Finais
No estágio maduro da aplicação de teste, adicionamos o mecanismo de descoberta recursiva e o mapa de estado links_map. O crawler extrai todos os elementos document.querySelectorAll('a[href]'), filtra âncoras e links externos, e navega progressivamente até zerar as URLs pendentes.
Veja a implementação definitiva presente em scripts/test_site_playwright_unittest.py:
|
|
3.6 Resultados da Execução
Ao executar a suíte, o unittest reporta a execução limpa de ponta a ponta:
|
|
Resumo e Pontos-Chave
- O desenvolvimento de software de qualidade começa com uma stack sólida e moderna (Spring Boot 4.1.2, Kotlin 2.4.21, Gradle 9.8.2 e Kotest 6.2.6).
- Para testar aplicações e documentações corporativas, construa suítes incrementais: comece validando a prontidão do servidor nos ganchos globais de setup (
setUpClass), integre o navegador headless e então expanda para grafos de descoberta com mapas de estado. - Testes End-to-End não precisam ser lentos ou frágeis: com Playwright e Devbox, testamos mais de 230 páginas dinâmicas em menos de 30 segundos com 100% de determinismo.