Relatórios, benchmark e CI
Quatro formatos, e a medição que mostra o p95 em vez de só a média.
Os formatos#
dataforge crucible # texto, colorido
dataforge crucible --formato=junit --out=r.xml
dataforge crucible --formato=json --out=r.json
dataforge crucible --formato=tap| Formato | Para |
|---|---|
| texto | ler no terminal |
| JUnit XML | GitHub Actions, GitLab, Jenkins — todos leem |
| JSON | processar por programa |
| TAP 13 | o formato mais simples e portável que existe |
O JUnit existe porque integrar com cada CI exigiria que cada um aprendesse o formato do Crucible — e nenhum vai aprender.
A ordem do relatório#
Primeiro o mapa, uma linha por suíte. Depois cada falha com espaço para respirar. Quem roda a suíte quer saber se está verde; quando não está, quer o detalhe de cada uma — e não rolar a tela procurando o vermelho no meio do verde.
Benchmark#
crucible "Desempenho":
bench "soma de mil" times 100:
total := 0
cycle i from 1 to 1000:
total += i ⏱ soma de mil: 0.0821ms media, 0.0798ms mediana,
p95 0.0954ms, 12180 ops/sPela biblioteca, com mais controle:
adopt Crucible
m := Crucible.benchmark("soma", lambda => sum(range(1000)), 500)
out m["media_ms"], m["mediana_ms"], m["p95_ms"], m["ops_por_s"]Ordem aleatória#
Um teste que só passa porque outro rodou antes é uma bomba-relógio. --aleatorio a detona cedo:
dataforge crucible --aleatorio
# ordem aleatoria, semente 1738 (--semente=1738 repete)
dataforge crucible --aleatorio --semente=1738 # reproduz exatamenteA semente aparece no relatório justamente para a falha ser reproduzível — uma ordem aleatória que não se repete é impossível de depurar.
Instabilidade#
dataforge crucible --repetir=20Roda cada trial vinte vezes. Um teste que passa às vezes depende de tempo, de ordem, ou de estado que sobrou — e é melhor descobrir isso agora que numa madrugada de plantão.
No CI#
name: testes
on: [push, pull_request]
jobs:
crucible:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- run: curl -fsSL https://dataforge-lang.vercel.app/instalar.sh | sh
- run: dataforge check src/ --strict
- run: dataforge big-o src/ --strict
- run: dataforge crucible --formato=junit --out=resultados.xml
- uses: actions/upload-artifact@v4
if: always()
with:
name: resultados
path: resultados.xmldataforge crucible sai com código 1 quando algo falha, então o passo reprova sozinho.
Lendo o resultado por programa#
adopt Crucible
Crucible.suite("Exemplo", lambda => [
Crucible.trial("passa", lambda => Crucible.expect(1).to_be(1))
])
resumo := Crucible.run()
out resumo["passou"], resumo["falhou"], resumo["verde"]
cycle r in Crucible.results():
out r["nome"], r["estado"], r["duracao"]