Test database state pollution between tests
April 30, 2026 · View on GitHub
Playbook ID: database-test-isolation
Category: test
Severity: medium
Tags: test, database, isolation, transaction, state
What this failure means
Tests are polluting a shared database with committed data that later tests did not expect to find. Tests pass in isolation but fail when the full suite runs, or fail only in certain orderings.
Common log signals
duplicate key value
UniqueConstraintViolation
IntegrityError
duplicate entry
expected count to be
PG::UniqueViolation
SQLSTATE 23505
violates unique constraint
Diagnosis
Each test is leaving committed rows, modified schema state, or other database changes that subsequent tests encounter as unexpected pre-existing data.
Typical symptoms:
already existsorduplicate keyerrors in tests that insert seed data.- Counts or queries that return more rows than expected.
- Tests pass individually but fail together or in a different order.
Fix steps
-
Wrap each test in a database transaction that is rolled back after the test:
-
Rails:
use_transactional_fixtures = true(default in RSpec Rails). -
Go (sqlx/pgx): begin a transaction in
TestMainort.Cleanup, pass it to the test, and roll back after:tx, _ := db.BeginTx(ctx, nil) defer tx.Rollback() -
Django:
TestCasewraps each test in a transaction automatically. UseTransactionTestCaseonly when testing transaction-specific behaviour.
-
-
For tests that cannot use transactions (e.g., testing COMMIT behaviour), use a dedicated test database and truncate all tables in a setup/teardown hook:
TRUNCATE TABLE users, orders, events RESTART IDENTITY CASCADE; -
Check for tests that use
TRUNCATEorDELETEon shared tables and commit — these affect concurrent parallel tests. Namespace test data with a unique run ID or isolate these tests in a separate database. -
Confirm the database is seeded once before the test suite and not accumulating inserts across test runs. Use a per-test factory (e.g.,
factory_boy,FactoryBot, Go test helpers) that inserts and cleans up its own data. -
Run tests in random order to surface all implicit ordering dependencies:
pytest --randomly-seed=<N> go test -shuffle=on ./...
Validation
- Run the full suite multiple times in random order and confirm zero failures caused by unexpected pre-existing data.
- Confirm each test asserts only on data it created, not on total row counts.
Likely files to inspect
docker-compose.yml.github/workflows/*.ymlmigrations/testdata/
Run Faultline
faultline analyze build.log
faultline explain database-test-isolation
faultline workflow build.log --json --mode agent
Search phrases this page answers
- Test database state pollution between tests
- Test: test database state pollution between tests
- violates unique constraint
- faultline explain database-test-isolation
Generated from playbooks/bundled/log/test/database-test-isolation.yaml. Do not edit directly — run make docs-generate.