Ţéšţ Šţŕàţéĝý
Þŕîñçîþļéš
- Éṽéŕý ƒöŕḿàţ àñđ ţööļ ĥàš ţéšţš. Ñö ƒöŕḿàţ ŕéàđéŕ/ŵŕîţéŕ öŕ ţööļ šĥîþš ŵîţĥöüţ ţéšţš.
- Ŕöüñđţŕîþ îš ţĥé ĝöļđ šţàñđàŕđ. Ƒöŕ ƒöŕḿàţš: ŕéàđ, ŵŕîţé, çöḿþàŕé ŵîţĥ öŕîĝîñàļ.
- Þöŕţ Okapi ţéšţ đàţà. Üšé Okapi'š ţéšţ ŕéšöüŕçé ƒîļéš àš ţĥé šöüŕçé öƒ ţŕüţĥ.
- Ţàƃļé-đŕîṽéñ ţéšţš. Ĝö'š ţàƃļé-đŕîṽéñ þàţţéŕñ ƒöŕ çöṽéŕîñĝ ḿüļţîþļé îñþüţš.
- Ţéšţ àţ ţĥé îñţéŕƒàçé ƃöüñđàŕý. Ţéšţ àĝàîñšţ
DataFormatReader/Toolîñţéŕƒàçéš, ñöţ îñţéŕñàļš. - Đéţéŕḿîñîšţîç ÀÎ ţéšţš. ÀÎ ţööļš üšé ḿöçķ þŕöṽîđéŕš îñ ÇÎ; ŕéàļ þŕöṽîđéŕš îñ ḿàñüàļ îñţéĝŕàţîöñ ţéšţš.
Ţéšţ Šţŕüçţüŕé
neokapi/
├── core/model/
│ ├── model_test.go # Block creation, targets, overlays
│ └── run_test.go # Run sequence (canonical inline content)
├── core/flow/
│ ├── executor_test.go # Flow execution, error propagation
│ └── steps_test.go # StepsToGraph compilation
├── core/tool/
│ └── base_test.go # BaseTool dispatch, pass-through
│
├── core/formats/
│ ├── html/
│ │ ├── reader_test.go
│ │ ├── writer_test.go
│ │ └── testdata/ # Test fixtures
│ └── ... (each format follows the same pattern)
│
├── core/ai/tools/
│ └── tools_test.go # AI tool tests; use mock provider
├── providers/ai/
│ └── mock.go # Mock LLM provider
│
└── core/internal/testutil/
└── helpers.go # Common test helpers (RawDocFrom*, CollectParts/Blocks, PartsToChannel)
Ţéšţ Þàţţéŕñš
Ŕöüñđţŕîþ Ţéšţ
Ţĥé ḿöšţ îḿþöŕţàñţ ţéšţ ƒöŕ àñý ƒöŕḿàţ:
func TestRoundTrip(t *testing.T) {
tests := []struct {
name string
file string
}{
{"simple", "testdata/simple.html"},
{"inline codes", "testdata/inline_codes.html"},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
original, err := os.ReadFile(tt.file)
require.NoError(t, err)
reader := NewReader()
err = reader.Open(ctx, testutil.RawDocFromReader(
bytes.NewReader(original), tt.file, model.LocaleEnglish))
require.NoError(t, err)
parts := testutil.CollectParts(t, reader.Read(ctx))
reader.Close()
var buf bytes.Buffer
writer := NewWriter()
writer.SetOutputWriter(&buf)
writer.Write(ctx, testutil.PartsToChannel(parts))
writer.Close()
assert.Equal(t, string(original), buf.String())
})
}
}
Éẋţŕàçţîöñ Ţéšţ
Ṽéŕîƒý šþéçîƒîç Ƃļöçķš àŕé éẋţŕàçţéđ ŵîţĥ çöŕŕéçţ çöñţéñţ:
func TestExtraction(t *testing.T) {
data, err := os.ReadFile("testdata/sample.html")
require.NoError(t, err)
reader := NewReader()
err = reader.Open(ctx, testutil.RawDocFromReader(
bytes.NewReader(data), "testdata/sample.html", model.LocaleEnglish))
require.NoError(t, err)
defer reader.Close()
blocks := testutil.CollectBlocks(t, reader.Read(ctx))
require.Len(t, blocks, 3)
assert.Equal(t, "Welcome", blocks[0].SourceText())
}
Ƒļöŵ Éẋéçüţîöñ Ţéšţ
Ƃüîļđ à ţööļ ƃý éḿƃéđđîñĝ tool.BaseTool àñđ šéţţîñĝ ĥàñđļéŕ ƒîéļđš, àššéḿƃļé à
ƒļöŵ ŵîţĥ ţĥé flow.NewFlow(...).AddTool(...).Build() ƃüîļđéŕ (ŵĥîçĥ ŕéţüŕñš
(*Flow, error)), àñđ đŕîṽé îţ ŵîţĥ ExecuteWithChannels ƒöŕ çĥàññéļ-ļéṽéļ
çöñţŕöļ:
func TestFlowExecution(t *testing.T) {
uppercase := &tool.BaseTool{
ToolName: "uppercase",
Produce: func(v tool.VariantView) error {
if v.Translatable() {
v.SetTargetText(model.LocaleFrench, strings.ToUpper(v.SourceText()))
}
return nil
},
}
f, err := flow.NewFlow("test").AddTool(uppercase).Build()
require.NoError(t, err)
executor := flow.NewExecutor()
in, out, wait := executor.ExecuteWithChannels(t.Context(), f)
go func() {
in <- &model.Part{Type: model.PartBlock, Resource: model.NewBlock("tu1", "hello")}
close(in)
}()
for range out { /* drain */ }
require.NoError(t, wait())
}
Ŕüññîñĝ Ţéšţš
make test # All tests
make test-unit # Unit tests only (-short)
make test-race # With race detector
make test-verbose # Verbose output
make cover # Coverage report
Šîñĝļé ţéšţ:
go test -tags fts5 ./core/flow/ -run TestFlowExecutorContextCancellation -v
Þàšš -tags fts5 ŵĥéñéṽéŕ ýöü ƃýþàšš make. Ţĥé ƃüîļđ šüççééđš ŵîţĥöüţ îţ, àñđ
öñļý à ǫüéŕý ţĥàţ ŕéàçĥéš ƑŢŠ5 (çöñţéñţ ḿéḿöŕý, ţéŕḿš) ƒàîļš àţ ŕüñţîḿé ŵîţĥ
no such function: fts5. Šþéļļ éṽéŕý ţàĝ îñ öñé çöḿḿà-šéþàŕàţéđ ƒļàĝ
(-tags "fts5,parity"): go ķééþš öñļý ţĥé ļàšţ -tags öççüŕŕéñçé.
Ţéšţ Ţàĝš
| Ţàĝ | Þüŕþöšé | Çöḿḿàñđ |
|---|---|---|
| (ñöñé) | Üñîţ ţéšţš öñļý | go test -tags fts5 ./... |
integration | + þļüĝîñ àñđ ƒöŕḿàţ îñţéĝŕàţîöñ | go test -tags "fts5,integration" ./... |
acceptance | + ñàţîṽé-ƒöŕḿàţ çöñšüḿéŕ-ţööļçĥàîñ ţéšţš | go test -tags "fts5,acceptance" ./... |
parity | + Okapi þàŕîţý çöḿþàŕîšöñ ţéšţš | go test -tags "fts5,parity" ./... |
e2e | + éñđ-ţö-éñđ ţéšţš | go test -tags "fts5,e2e" ./... |
ÇÎ
Ţéšţš ŕüñ àüţöḿàţîçàļļý ṽîà ĜîţĤüƃ Àçţîöñš öñ éṽéŕý þüšĥ àñđ þüļļ ŕéǫüéšţ. Šéé .github/workflows/ci.yml.