Helpers¶
Project-Specific Helpers¶
Create reusable test helpers for your project by wrapping common overrides.
Creating Helpers¶
Create a separate file in your tests directory:
tests/my_helpers.go
package main
import "github.com/karlderkaefer/kcl-test/pkg/kcltest"
// Project-specific convenience functions
func WithTeamName(name string) kcltest.TestOption {
return kcltest.WithStringOverride(
[]string{"oxr", "spec", "resourceConfig", "teamName"},
name,
)
}
func WithRegion(region string) kcltest.TestOption {
return kcltest.WithStringOverride(
[]string{"oxr", "spec", "resourceConfig", "btpRegion"},
region,
)
}
func WithEnvironment(env string) kcltest.TestOption {
return kcltest.WithStringOverride(
[]string{"oxr", "spec", "environment"},
env,
)
}
Using Helpers¶
assertion := kcltest.NewKCLAssertion(t, mainKCLPath).
WithTestInput(
WithTeamName("my-team"),
WithRegion("eu10"),
WithEnvironment("production"),
)
Benefits
- Readable tests:
WithTeamName("my-team")is clearer than raw path arrays - Maintainable: Change paths in one place when schema changes
- Type-safe: Compile-time checks for helper function signatures
Structured Errors¶
The framework provides structured error types for better debugging.
AssertionError¶
err := &kcltest.AssertionError{
Type: kcltest.AssertionTypeEqual,
Kind: "Subaccount",
Path: "spec.forProvider.region",
Index: -1, // or item index for multi-item assertions
Expected: "eu10",
Actual: "us-east-1",
Message: "Region should match expected value",
}
Output:
Subaccount: expected 'eu10' at 'spec.forProvider.region', got 'us-east-1' - Region should match expected value
Error Collection¶
errs := &kcltest.AssertionErrors{}
errs.Add(err1)
errs.Add(err2)
if errs.HasErrors() {
fmt.Println(errs.Error())
}
Error Types¶
| Type | Description |
|---|---|
AssertionTypeEqual |
Value equality check failed |
AssertionTypeExists |
Expected item/path to exist |
AssertionTypeNotExists |
Expected item/path to not exist |
AssertionTypeCount |
Item count mismatch |
AssertionTypeMatches |
Custom matcher function failed |
AssertionTypeItemNotFound |
Resource kind not found |
AssertionTypePathNotFound |
Path not found in resource |
Environment Variables¶
| Variable | Description |
|---|---|
UPDATE_SNAPS=true |
Update snapshots instead of comparing |
Best Practices¶
Organize Test Files¶
tests/
├── helpers.go # Project-specific helpers
├── composition_test.go # Main composition tests
├── input.yaml # Default test input
└── snapshots/ # Snapshot files
└── TestComposition.snap
Reusable Test Fixtures¶
tests/fixtures.go
package main
import "github.com/karlderkaefer/kcl-test/pkg/kcltest"
// Common test configurations
var (
DefaultHooks = kcltest.ChainHooks(
kcltest.NewDefaultsHook(map[string]any{
"ctx": defaultContext,
}),
kcltest.NewFilterHook(excludeUsageResources),
)
)
func excludeUsageResources(item map[string]any) bool {
kind, _ := kcltest.GetByPath[string](item, "kind")
return kind != "Usage"
}
var defaultContext = map[string]any{
"apiextensions.crossplane.io/environment": map[string]any{
"region": "eu10",
},
}
Table-Driven Tests¶
func TestRegions(t *testing.T) {
tests := []struct {
name string
region string
expected string
}{
{"EU region", "eu10", "eu-central-1"},
{"US region", "us10", "us-east-1"},
{"AP region", "ap10", "ap-southeast-1"},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
assertion := kcltest.NewKCLAssertion(t, mainKCLPath).
WithTestInput(
kcltest.WithInputFile("input.yaml"),
WithRegion(tt.region),
)
assertion.AssertPath(
"Subaccount",
"spec.forProvider.awsRegion",
tt.expected,
)
})
}
}