Testing
DataKit uses a layered test strategy: fast unit tests for packages, Docker-backed integration tests for external behavior, and end-to-end tests that exercise the CLI workflow from package scaffolding through build.
flowchart LR
U[Unit tests] --> I[Integration tests]
I --> E[E2E tests]
U --> T[Transform package checks]
T --> E
Make targets
Run the standard targets from the repository root:
make test-unit
make test-integration
make test-e2eThese targets are defined in the root Makefile:
make test-unitruns unit tests acrosscontracts/,sdk/,cli/, andplatform/controller/make test-integrationruns Docker-backed integration suites such assdk/promotion/...make test-e2erunsgo test -v ./...undertests/e2e
Unit test patterns
The codebase consistently uses standard Go test structure:
- table-driven tests with
t.Run(...) *_test.gofiles beside the package under testt.TempDir()for disposable package directories and fixtures- direct assertions against parsed manifests, flags, and result structs
Examples you can copy from the codebase:
sdk/runner/runner_test.govalidatesRunOptionswith table-driven casescli/cmd/run_test.goandcli/cmd/test_test.gowrite minimaldk.yamlfiles intot.TempDir()tests/e2e/helpers.gocentralizes helpers such ascreateTempDir()andassertFileExists()
Integration tests
Integration tests require Docker and exercise behavior that depends on external systems.
The root Makefile calls these with the integration build tag:
cd sdk && go test -v -tags integration ./promotion/...
cd platform/controller && go test -v -tags integration ./internal/controller/...Use integration tests when the behavior depends on container runtime access, registry interactions, or controller reconciliation logic that unit tests cannot model faithfully.
End-to-end tests
The E2E suite under tests/e2e/ validates the CLI workflow itself.
tests/e2e/workflow_test.go covers the expected init → lint → build loop, and
also iterates across generic-go, generic-python, dbt, and cloudquery
runtimes.
Use E2E tests to prove that a user can successfully:
- scaffold a package
- generate
dk.yaml - lint the package
- build it with
--dry-run
Writing tests for transforms
When you add or change transform behavior, mirror the patterns already used in CLI and runner tests:
- Create a disposable package directory with
t.TempDir() - Write the minimal
dk.yamlneeded for the scenario - Prefer
dk test <package>or runner dry-runs for fast validation paths - Assert on status, exit behavior, and generated files instead of logs alone
A representative runner pattern from sdk/runner/docker_test.go is:
result, err := runner.Run(context.Background(), RunOptions{
PackageDir: tmpDir,
DryRun: true,
})A representative CLI pattern from cli/cmd/test_test.go is to write a transform
manifest into t.TempDir() and then call runTest(cmd, []string{tmpDir}).