testertest*.py convention appears in ~25 project directories; understanding its role vs. test_*.py clarifies the project's testing strategyDate: 2026-05-29
Time: 07:36
testertest*.py vs test_*.py ConventionThis project uses a two-tier testing strategy: each implementation directory contains both a test*.py file and a testertest_*.py file. They look similar at first glance — both use pytest conventions, both test the same module — but they serve different roles in the development pipeline.
testertest*.py: The Spec Verification SuiteThese files are generated as part of the implementation task. They're written by the "tester" stage of the code-expert workflow — an LLM agent that reads the implementation spec and produces tests that verify the spec's requirements are met.
Key characteristics:
consistent-hashing/testertestconsistenthashing.py:7, testdeterminism has a docstring """Same key always maps to same node.""" — this reads like a spec requirement, not a developer's unit test.testertestbtree.py:8 ("""Test basic insert and lookup from the example usage.""") with testbtree.py:8 (no docstring, just def testbasic). The tester files consistently document *what requirement* each test validates.testertestbtree.py ends with print("testxxx PASSED") (lines 46, 65, 83, etc.) and includes a main_ block (line 192) that runs all tests sequentially. This suggests they were designed to run standalone, outside pytest, as a quick validation pass.testertestbtree.py has 8 tests covering the core operations. test_btree.py has 10+ tests and goes deeper — WAL recovery (line 119), uncommitted WAL entries (line 144), delete freeing empty leaves (line 171).test_*.py: The Developer Test SuiteThese are the comprehensive tests that go beyond spec verification:
testbtree.py:testwalrecovery (line 119) simulates a crash by closing file handles directly (tree.pm.f.close()) — this tests internal recovery mechanics, not a user-facing spec requirement.testbtree.py:testwaluncommittedentries (line 144) imports internal types (from btree import WAL, serializeleaf, HEADER_FMT, LEAF) and manually writes WAL entries. The tester file never touches internals.testconsistenthashing.py includes testduplicateaddidempotent (line 108), testringpositionvalidrange (line 114), testscalability (line 120), and testvnodecountaffectsbalance (line 153) — none of which appear in the tester version.Not every project follows the exact testertest*.py pattern. leaderless-replication/testdynamotester.py inverts the convention to test*tester.py, and unbundled-database/testtestervalidation.py uses yet another variant. The docstring in testdynamotester.py:1 — """QA tester tests for Dynamo-style leaderless replication.""" — confirms the "tester" label refers to the QA/validation role regardless of filename ordering. The unbundled-database/testtestervalidation.py file (line 1: """Tester-stage validation: edge cases and spec example verification.""") makes this even more explicit: these are "tester-stage" artifacts with classes like TestSpecExample that replay the exact usage from the spec.
The split reflects the code-expert workflow documented in CLAUDE.md: implementations are built by an LLM pipeline that generates code from DDIA-based specs. The tester files are a correctness gate — "does this implementation satisfy what the spec asked for?" The developer test files are the robustness layer — "does this implementation handle crashes, edge cases, and internal invariants correctly?" Running pytest picks up both (all files match test*.py or *test*.py), so the full suite runs together, but the tester files could also run standalone via python testertest_*.py.
tester-generation-pipeline — How the code-expert workflow generates testertest*.py files from specs, and whether they're regenerated when specs changeunbundled-database/testtestervalidation.py — The most explicit tester file: class names (TestSpecExample, TestEdgeCases) reveal the tester stage's internal structureleaderless-replication/testdynamotester.py — Uses the inverted naming convention; worth checking if the naming inconsistency reflects an evolution in the project's conventionstest-coverage-gaps — Whether tester files ever test things the developer suite doesn't, or if the developer suite is always a strict supersetb-tree-storage-engine/test_btree.py — Lines 119-183 show the depth gap: WAL crash recovery, internal state manipulation, and page-freeing tests that the tester file never touchestester-files-are-spec-verification — testertest*.py files verify spec requirements with docstrings and print-based reporting; test_*.py files test implementation internals and edge casestester-files-never-import-internals — Tester test files import only the public API (e.g., from btree import BTree), while developer test files import internal types like WAL, serializeleaf, and HEADER_FMTtester-files-run-standalone — Every testertest*.py includes a _main_ block that calls each test function sequentially, independent of pytestnaming-convention-not-uniform — The tester/test split uses at least three naming patterns: testertest*.py, test*tester.py, and testtester*.py across different project directoriesboth-suites-discoverable-by-pytest — Both naming conventions match pytest's default collection patterns, so pytest in any project directory runs the full combined suite