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 nobuild.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 nomavenLocala partir doxadm-commonsantes de buildar (o bloco dobuild.gradle.ktssó aceitabr.com.xadmdali, depois do registro). Com o registro fora do ar,./gradlew --offlineresolve 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.