Pular para conteúdo

Como buildar e testar

Status: Aprovado · Responsável: Gustavo Madruga · Atualizado em: 2026-09-15

Audiência: dev que precisa buildar e testar localmente. Subir o app em dev está em Como rodar.

Requisitos

  • Java 25, preferencialmente GraalVM, disponível no JAVA_HOME (toolchain pinada no build.gradle.kts: JavaLanguageVersion.of(25); instale via SDKMAN).
  • Docker em execução — os testes de integração (Testcontainers) sobem Postgres/Mongo/Garage reais.
  • Build tool: Gradle (./gradlew) — nunca Maven.
  • Lib da casa em versão ainda não publicada vem do ~/.m2: publique-a no mavenLocal a partir do xadm-commons antes de buildar (o bloco do build.gradle.kts só aceita br.com.xadm dali, depois do registro). Com o registro fora do ar, ./gradlew --offline resolve pelo cache e pelo ~/.m2.

Recomendações de ambiente

  • VS Code para editar (extensões de Java/Gradle ajudam).
  • Claude Code — como plugin no VS Code ou a CLI no terminal; as regras de IA do repo estão no CLAUDE.md.
  • Remote do Forgejo (fonte.xadm.biz/xadm/vantroba-bi-xls) configurado, com credencial — é o git de origem. O CI roda no espelho do GitHub (ver Deploy).
  • SDKMAN para instalar/alternar JDKs (a GraalVM 25 do projeto).

Buildar

./gradlew shadowJar                                          # app.jar local (fallback JVM)
docker build -f Dockerfile.native -t vantroba-xls:native .   # o mesmo build do job build_native do CI
./gradlew check                                              # compila + checkstyle + todos os testes (integração inclusa — precisa de Docker)

O deploy não usa artefato buildado aqui nem builda no Coolify: a imagem native é buildada no runner do GitHub Actions e o Coolify só puxa a imagem pronta — ver Deploy. O Dockerfile JVM fica como fallback: o build.targets do docs/app.json só tem native.

As 4 camadas de teste

Camada O que cobre Como roda
Unitário lógica pura (parsers, conversores, limites) ./gradlew test
Conformidade golden (Java×Python) paridade do parse Java com o resultado do fluxo Python legado ./gradlew test — compara contra fixtures golden
Integração (Testcontainers) repositórios, UPSERT diff-aware, storage Garage, reset — contra Postgres/Mongo/Garage reais ./gradlew test (@IntegracaoDocker — precisa de Docker)
Arquitetura (ArchUnit) sem ciclos entre as features de topo; comum não depende de feature; processamento.processing não depende da camada HTTP (0022) ./gradlew test
./gradlew test    # tudo: unitário + conformidade + ArchUnit + integração
./gradlew check   # o mesmo + checkstyle — é o gate do CI

Os testes de integração (@IntegracaoDocker da xadm-comum-teste, que marca a tag docker e liga a DockerDisponivelCondition da lib) rodam por padrão; a flag -PdockerTests não existe mais. Sem Docker, eles são pulados — com DOCKER AUSENTE — teste de integração PULADO em ERROR no log e o teste marcado skipped no relatório. Um BUILD SUCCESSFUL sem Docker não prova a integração; o CI roda com Docker.

O Postgres de teste é o singleton da xadm-comum-teste (um container por JVM). O AbstractRepositoryIntegrationTest limpa só as tabelas que os testes gravam, porque a V10 semeia o cadastro de veículos, que a limpeza da lib apagaria.

Travas: a task test tem teto de 15 min, cada teste tem 2 min (src/test/resources/junit-platform.properties, desligado sob debug) e o pool de teste espera conexão por 5 s (application-test.yml). Travamento vira falha com causa, não CI pendurado.

Fixtures de conformidade

Em src/test/resources/fixtures/transporte-YYYYMMDD/:

  • input.xlsx — a planilha do período (derivada de uma planilha real, anonimizada).
  • resultado-python.json — o golden (saída do fluxo Python) a bater.

Uma fixture por período; o teste de conformidade roda a saída Java contra o golden.

Fixture nova nasce anonimizada

As planilhas de origem são reais (dado de cliente). Antes de commitar, rode python scripts/anonimizar-fixtures.py src/test/resources/fixtures/transporte-YYYYMMDD: ele troca nome de motorista/gestor, CPF e o CNPJ da empresa por fakes determinísticos, em lockstep no input.xlsx e no resultado-python.json (mesma substituição nos dois, preservando shape e resultado — a conformidade segue verde). Permanecem reais (decisão explícita, REGRA Nº 3): placas, municípios, segmentos e os valores numéricos — não são dado pessoal e são computados pelo parser, então trocá-los exigiria regenerar o oracle Python. A receita completa está no javadoc do ProcessamentoConformidadeTest.

Paridade não cobre os 5 campos de frota (ainda)

O teste de conformidade remove os 5 campos de cadastro de veículo/frota (tipo de frota, marca, modelo, ano de construção, ano de modelo) antes de comparar — o exportar-json.py do fluxo Python ainda não exporta esses campos. Ou seja: a paridade Java×Python cobre tudo menos esses 5 campos, até o script Python ser alinhado. Os campos em si são testados pelos testes de cadastro de frota (ver etapa 04).

Fixture sintética de teste unitário sai do XlsxFixtureWriter (FastExcel-writer): texto, número e data numérica com formato (data(linha, coluna, LocalDate)), que o ExcelProcessor lê como data porque abre o workbook com ReadingOptions(true, false).

Contrato do arquivo

O layout das abas e o resultado canônico estão em schema-processamento-xls.json.