TiDB Test Placement and Writing
Quick workflow
- Identify the target package and existing coverage using
rg --files -g '*_test.go'andrg --files -g '*.json'. - Check
BUILD.bazelforshard_countin the target directory; keep test count <= 50 per directory. - For optimizer cases, place new tests under
pkg/planner/core/casetest/<type>(seereferences/planner-guide.md). - Reuse existing fixtures and testdata; add new files only when necessary.
- Name tests descriptively; avoid issue-id-only names (e.g.,
TestIssue123456). - Merge same-functionality cases into a single test only if runtime remains reasonable.
- When moving tests/benchmarks, update
BUILD.bazelandMakefile(bench-daily) if needed.
Basic writing rules
- Benchmarks (
func BenchmarkXxx) are tests too; apply the same placement and naming rules (benchmarks do not count toward shard_count test limits). - Prefer table-driven tests for related scenarios in the same behavior area.
- Reuse existing helper setups and test fixtures; avoid re-creating schemas unless required.
- Prefer one
store+ onetestkitper test; when a single test covers multiple scenarios, use distinct table names and restore any session/system variables to their original values. - If a test must use multiple sessions or domains (for example, cross-session cache behavior), keep the extra stores/testkits but document why in the test.
- Keep per-test runtime short; consolidate similar checks only if runtime stays reasonable.
- Use behavior-based test names; never use issue-id-only names.
- In test code, use the variable name
tkfor*testkit.TestKit(avoidtestKit). - When merging multiple tests into one, keep a single
storeand a singletkunless multi-session behavior is required; do not create a new store/tk inside the same test body without a documented reason.
Placement rules
- Test count limit: Keep <= 50 tests per directory; align with
shard_countin the directoryBUILD.bazel(benchmarks are excluded).
Reference files
- Package case maps:
references/<pkg>-case-map.mdfor each top-level directory underpkg/ - Planner core placement guide:
references/planner-guide.md
Notes
- Apply the same rules (placement, shard_count, naming) to other packages beyond
pkg/planner. - Use existing testdata patterns (
*_in.json,*_out.json,*_xut.json) in the same directory when extending suites. When tests use testdata, run with-record --tags=intestas needed. - For
pkg/planner/core/casetest/rulepredicate pushdown cases, keep SQL inpredicate_pushdown_suite_in.jsonand record bothEXPLAIN format='brief'and query results via the test runner (seerule_predicate_pushdown_test.go). - When moving benchmarks between packages, update any
TestBenchDailywrappers that list them and keepMakefilebench-dailyentries aligned with the new package location. - When updating tests in any
pkg/*package, ask AI to update the corresponding case map underreferences/. - When updating tests in any other directory, also update this skill: add or extend a case map under
references/and add guidance in thisSKILL.mdso future changes stay consistent. - When merging issue regression tests into existing behavior tests, keep the issue id in SQL comments (e.g.
/* issue:12345 */) or nearby comments for traceability. - Prefer unit tests over
tests/integrationtestfor end-to-end coverage unless you need to avoid union-storage executor differences or require full workflow validation. - When tests read source files under Bazel, use
go/runfilesand ensure the target file is exported viaexports_files()in its owningBUILD.bazel. - For Bazel runfiles, be ready to include the workspace prefix (from
TEST_WORKSPACE) in the runfile path if needed. - Validation (Bazel): run
make bazel_preparefirst; then check the packageBUILD.bazelfor@com_github_pingcap_failpoint//:failpointdependency.- If present, run:
make bazel-failpoint-enablebazel test --norun_validations --define gotags=deadlock,intest --remote_cache=https://cache.hawkingrei.com/bazelcache --noremote_upload_local_results //path/to/package/...make bazel-failpoint-disable
- If absent, run
bazel testdirectly against the package path.
- If present, run: