The testing Skill — A Pyramid With Teeth
How the testing skill structures verification across unit, integration, and E2E layers — and the specific rules that prevent mocks from creating a false sense of safety.
Tests that pass while production fails are worse than no tests at all — they create confidence in something untrue. The testing skill is built around eliminating that class of failure. It is structured as an entry file plus a set of targeted fragments, each addressing a distinct failure mode.
The pyramid baseline is familiar: 70% unit tests, 20% integration tests, 10% E2E tests. Unit tests mock all external dependencies. Integration tests cover module-to-database interaction. E2E tests cover critical user flows. These proportions are targets, not aspirations — CI fails on missing or failing tests.
The mock boundary problem
The skill's mocking rules contain one constraint that is easy to miss: never mock the thing being tested. If a bug class lives in the real integration — wrong client, wrong schema, wrong SQL dialect — a mocked unit test passes and production fails. This is why the skill routes specific scenarios to a live-smoke-gates.md fragment: raw SQL, cross-datasource code, Docker orchestration, and bulk ingest operations all require a live smoke test, not a mock.
A second boundary problem is driver-side serialization. When a unit test captures database driver mock parameters and asserts column-shape invariants, the test captures values before the driver applies its own serialization. A real driver may JSON-serialize an array binding into a column; the mock silently accepts the raw array. The skill mandates a simulateDriverBind(p) helper that reproduces the driver's serialization rules, cited to the driver documentation, applied to every unit test of a DB writer with a column format contract.
Self-validating assertions
Existence assertions — "element renders any text," "counter is non-empty" — catch only the case where nothing rendered at all. They pass even when the system is broken. The skill requires self-validating assertions instead: after a triggering interaction, poll the flipped target state. A checkbox test should poll isChecked() against the known opposite of its pre-click state, not merely confirm that text exists somewhere. The origin of this rule is concrete: an assertion first written as "counter renders any text" passed even when the toggle was visibly broken.
Fragment routing
The skill deliberately keeps the entry file short and routes to fragments on demand. tdd-discipline.md covers the RED-GREEN-REFACTOR cycle and pre-answers the common rationalizations against test-first. silent-failure-detection.md handles CLI wrappers that exit with code 0 on error and write error sentences to stdout. bats-and-spec-lint.md covers shell script testing. triaging-legacy-failures.md provides three-bucket triage for inherited red test suites. Loading only the relevant fragment keeps context cost low during every QA or implementation cycle.
The testing skill connects directly to the systematic-debugging skill — Phase 4 of systematic debugging requires creating a failing test before any fix. Stack-level test framework choices come from the tech-stack skill. For the overall Datarim workflow, see what is Datarim.