Skip to content

Commit 6bbe205

Browse files
docs: add CI test generation guide to claude-doc
Step-by-step reference for replicating the auto test generation workflow (Claude API + GitHub Actions) in any Android/KMP repo. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
1 parent 0d465a8 commit 6bbe205

1 file changed

Lines changed: 269 additions & 0 deletions

File tree

claude-doc/step_command_ci_test.md

Lines changed: 269 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,269 @@
1+
# Auto Test Generation with Claude API — Step by Step
2+
3+
Guia completo para replicar o fluxo de geração automática de testes unitários
4+
usando Claude API + GitHub Actions em qualquer repositório Android/KMP.
5+
6+
---
7+
8+
## Visão geral do fluxo
9+
10+
```
11+
PR aberto
12+
→ CI passa (pr.yml)
13+
→ Workflow dispara (generate-tests.yml)
14+
→ Escaneia arquivos sem cobertura
15+
→ Chama Claude API para cada arquivo
16+
→ Gera arquivos *Test.kt
17+
→ Cria branch + abre PR automático com os testes
18+
```
19+
20+
---
21+
22+
## Fase 1 — Análise do módulo
23+
24+
Antes de configurar qualquer coisa, entenda o que existe no módulo alvo.
25+
26+
**O que fazer:**
27+
- Mapear todos os arquivos `.kt` de produção (`commonMain`, `androidMain`)
28+
- Verificar se já existem testes em `src/test/java/`
29+
- Identificar quais arquivos têm ou não cobertura
30+
- Anotar o padrão de pacote (ex: `com.github.codandotv.craftd.androidcore`)
31+
32+
**Comando útil para listar arquivos sem teste:**
33+
```bash
34+
while IFS= read -r SRC; do
35+
TEST=$(echo "$SRC" \
36+
| sed 's|src/commonMain/kotlin/|src/test/java/|' \
37+
| sed 's|src/androidMain/kotlin/|src/test/java/|' \
38+
| sed 's|\.kt$|Test.kt|')
39+
if [ ! -f "$TEST" ]; then
40+
echo "SEM TESTE: $SRC"
41+
fi
42+
done < <(find <seu-modulo>/src \
43+
\( -path "*/commonMain/kotlin/*.kt" -o -path "*/androidMain/kotlin/*.kt" \) \
44+
| grep -v "Test\.kt" | sort)
45+
```
46+
47+
---
48+
49+
## Fase 2 — Criar o script Python
50+
51+
Crie o arquivo `.github/scripts/generate_tests.py`.
52+
53+
**Responsabilidades do script:**
54+
- Receber a lista de arquivos via `CHANGED_FILES` (env var) ou args
55+
- Para cada arquivo, verificar se o teste já existe — se sim, pular
56+
- Converter o path fonte → path de teste:
57+
- `src/commonMain/kotlin/Foo.kt``src/test/java/FooTest.kt`
58+
- `src/androidMain/kotlin/Bar.kt``src/test/java/BarTest.kt`
59+
- Chamar a Claude API com o conteúdo do arquivo
60+
- Escrever o arquivo `*Test.kt` gerado no path correto
61+
- Exportar outputs para o GitHub Actions (`generated_count`, `covered_names`)
62+
63+
**Modelo recomendado:** `claude-haiku-4-5-20251001`
64+
> Muito mais barato que Opus (~10x) e suficiente para gerar testes de data classes,
65+
> extension functions, DiffUtil callbacks e enums.
66+
67+
**Custo estimado:** ~$0.09 para 17 arquivos com Haiku.
68+
69+
**Prompt que funcionou bem:**
70+
```
71+
Você é um expert em Kotlin/KMP. Gere testes JUnit4 + MockK para o arquivo abaixo.
72+
- Pacote: {package_name}
73+
- Classe de teste: {ClassName}Test
74+
- Nomenclatura: backtick notation `given X when Y then Z`
75+
- Data classes: construção, defaults, copy(), equals/hashCode
76+
- Extension functions com JsonElement: null, JSON válido, JSON inválido
77+
- DiffUtil: areItemsTheSame e areContentsTheSame (incluindo AbstractMap)
78+
- Enums: verificar todos os valores via enumValueOf
79+
- Retorne APENAS o arquivo .kt, sem markdown, sem explicação.
80+
```
81+
82+
---
83+
84+
## Fase 3 — Criar o workflow
85+
86+
Crie o arquivo `.github/workflows/generate-tests.yml`.
87+
88+
**Triggers necessários:**
89+
```yaml
90+
on:
91+
workflow_dispatch: # execução manual pelo Actions UI
92+
inputs:
93+
override_files:
94+
description: 'Opcional: arquivos .kt específicos. Vazio = escaneia tudo.'
95+
required: false
96+
default: ''
97+
98+
workflow_run: # automático após o CI passar
99+
workflows: ["Nome exato do seu workflow de CI"]
100+
types: [completed]
101+
```
102+
103+
> ⚠️ `workflow_run` só funciona se o arquivo do workflow estiver na branch **default (main)**.
104+
> Enquanto o PR não for mergeado, o trigger automático não dispara.
105+
106+
**Permissões necessárias:**
107+
```yaml
108+
permissions:
109+
contents: write
110+
pull-requests: write
111+
```
112+
113+
**Condição do job:**
114+
```yaml
115+
if: |
116+
github.event_name == 'workflow_dispatch' ||
117+
(
118+
github.event.workflow_run.conclusion == 'success' &&
119+
github.event.workflow_run.actor.login != 'github-actions[bot]'
120+
)
121+
```
122+
> O check do bot evita loop infinito quando o próprio workflow abre um PR.
123+
124+
**Steps do job (em ordem):**
125+
126+
| Step | O que faz |
127+
|------|-----------|
128+
| Resolve trigger context | Normaliza `head_sha` e `pr_number` para os dois gatilhos |
129+
| Checkout | Usa `GH_PAT` (não `GITHUB_TOKEN`) para permitir push |
130+
| Set up Python | Versão 3.11 |
131+
| Install dependencies | `pip install anthropic` |
132+
| Find uncovered files | `find` nos diretórios `commonMain` e `androidMain` |
133+
| Generate tests | Chama `generate_tests.py` com `CHANGED_FILES` |
134+
| Check generated files | Usa `find` (não `git status`) para contar `*Test.kt` |
135+
| Commit tests | `git add --force` + push para nova branch |
136+
| Open PR | Usa `GH_TOKEN: ${{ secrets.GH_PAT }}` |
137+
138+
---
139+
140+
## Fase 4 — Secrets necessários no repositório
141+
142+
Configure em: **Settings → Secrets and variables → Actions**
143+
144+
| Secret | Como obter | Para que serve |
145+
|--------|-----------|----------------|
146+
| `ANTHROPIC_API_KEY` | console.anthropic.com → API Keys | Autenticar chamadas à Claude API |
147+
| `GH_PAT` | github.com → Settings → Developer settings → Personal access tokens (classic) → escopo `repo` | Permitir que o workflow abra PRs |
148+
149+
> ⚠️ **Por que `GH_PAT` e não `GITHUB_TOKEN`?**
150+
> O `GITHUB_TOKEN` tem restrição de segurança que impede a criação de PRs
151+
> que poderiam disparar outros workflows. O PAT pessoal não tem essa limitação.
152+
153+
---
154+
155+
## Fase 5 — Armadilhas encontradas (e como evitar)
156+
157+
### ❌ `git status --short` não detecta os arquivos gerados
158+
**Causa:** O diretório `src/test/java/` não existia no repo. O git lista diretórios
159+
novos como um único item untracked, sem expandir os arquivos dentro.
160+
161+
**Solução:** Usar `find` para contar e listar os arquivos gerados:
162+
```bash
163+
COUNT=$(find seu-modulo/src/test -name "*Test.kt" 2>/dev/null | wc -l | tr -d ' ')
164+
```
165+
166+
---
167+
168+
### ❌ `git add` não staged os arquivos de teste
169+
**Causa:** Diretório novo não rastreado pelo git.
170+
171+
**Solução:** Usar `git add --force`:
172+
```bash
173+
git add --force seu-modulo/src/test/
174+
```
175+
176+
---
177+
178+
### ❌ `workflow_run` usa a versão do workflow da `main`, não do PR
179+
**Causa:** Por design do GitHub Actions — `workflow_run` sempre lê o arquivo
180+
do workflow da branch default.
181+
182+
**Solução:** Mergear o PR do workflow para a `main` antes de testar o fluxo automático.
183+
Para testar antes do merge, use `workflow_dispatch` manualmente.
184+
185+
---
186+
187+
### ❌ Actions não consegue criar PR (permission error)
188+
**Causa:** `GITHUB_TOKEN` não tem permissão para abrir PRs que disparam workflows.
189+
190+
**Solução:** Criar um PAT pessoal com escopo `repo`, salvar como secret `GH_PAT`
191+
e usar `GH_TOKEN: ${{ secrets.GH_PAT }}` no step de criação de PR.
192+
193+
---
194+
195+
### ❌ Saldo insuficiente na Anthropic API
196+
**Causa:** A API key estava correta mas a conta não tinha créditos.
197+
198+
**Solução:** Adicionar créditos em console.anthropic.com → Plans & Billing.
199+
Com Haiku, $5 cobrem ~50 execuções completas do módulo.
200+
201+
---
202+
203+
## Fase 6 — Como testar antes do merge
204+
205+
**Opção 1 — Rodar o script localmente:**
206+
```bash
207+
source ~/.bash_profile # ou export ANTHROPIC_API_KEY=sk-ant-...
208+
209+
CHANGED_FILES=$(
210+
while IFS= read -r SRC; do
211+
TEST=$(echo "$SRC" \
212+
| sed 's|src/commonMain/kotlin/|src/test/java/|' \
213+
| sed 's|src/androidMain/kotlin/|src/test/java/|' \
214+
| sed 's|\.kt$|Test.kt|')
215+
[ ! -f "$TEST" ] && echo "$SRC"
216+
done < <(find <seu-modulo>/src \
217+
\( -path "*/commonMain/kotlin/*.kt" -o -path "*/androidMain/kotlin/*.kt" \) \
218+
| grep -v "Test\.kt" | sort)
219+
) python3 .github/scripts/generate_tests.py
220+
```
221+
222+
**Opção 2 — Após mergear, usar `workflow_dispatch`:**
223+
```
224+
GitHub → Actions → Auto Generate Cover+Test → Run workflow
225+
```
226+
Deixe o campo vazio para escanear tudo, ou informe arquivos específicos.
227+
228+
---
229+
230+
## Fase 7 — Verificar se funcionou
231+
232+
Após o workflow rodar, verifique:
233+
234+
1. **Step "Find uncovered Kotlin files"** — lista os arquivos detectados
235+
2. **Step "Generate unit tests with Claude API"** — cada arquivo deve mostrar `[OK] Written: ...`
236+
3. **Step "Check generated files"** — deve mostrar `Found N test file(s)`
237+
4. **Step "Open Pull Request"** — URL do PR gerado aparece no log
238+
5. **PR aberto automaticamente** com os testes em `src/test/java/...`
239+
240+
---
241+
242+
## Estrutura de arquivos criados
243+
244+
```
245+
.github/
246+
├── scripts/
247+
│ └── generate_tests.py # Script Python que chama a Claude API
248+
└── workflows/
249+
├── pr.yml # CI existente (build + test)
250+
└── generate-tests.yml # Workflow de geração automática de testes
251+
252+
<seu-modulo>/
253+
└── src/
254+
└── test/
255+
└── java/
256+
└── com/... # Testes gerados espelhando o pacote do fonte
257+
```
258+
259+
---
260+
261+
## Checklist rápido para um novo repo
262+
263+
- [ ] Identificar o módulo alvo e mapear arquivos sem cobertura
264+
- [ ] Criar `.github/scripts/generate_tests.py`
265+
- [ ] Criar `.github/workflows/generate-tests.yml` apontando para o nome correto do CI
266+
- [ ] Adicionar secret `ANTHROPIC_API_KEY` (console.anthropic.com)
267+
- [ ] Adicionar secret `GH_PAT` (PAT com escopo `repo`)
268+
- [ ] Abrir PR com os arquivos do workflow e mergear para `main`
269+
- [ ] Abrir qualquer PR tocando o módulo alvo e acompanhar o Actions

0 commit comments

Comments
 (0)