| name | integration-test-pattern |
| description | Trigger: testing external dependencies, databases, queues, testcontainers. Prefer real dependencies over mocks for integration-level tests. |
Trigger Conditions
Load this skill when a test needs to exercise a real external dependency —
a database, a queue, a cache, or another service the code under test talks
to. This includes any test tagged as an integration or acceptance scenario
in Gherkin (PRD §2, the gate_integration/gate_e2e steps of §4.5).
Practice: Integration Over Unit (PRD §2, Tooling Baseline §2.3)
FreIA prioritizes integration tests with real dependencies (via
testcontainers, or the project's local docker-compose.dev services)
over mocked unit tests wherever the behavior under test crosses a real
boundary (SQL, message broker, HTTP client to a third party). Mocks hide
integration bugs; a testcontainers-backed test catches them.
- Spin up the dependency via
testcontainers (or the local
docker-compose.dev services) — never a mock of the driver/client for
these boundaries.
- Local reproducibility is mandatory: the test must run via
devenv shell
with no cloud-only infra.
- Cover the sad path here too — connection failures, timeouts, constraint
violations — not only the happy path.
- Integration tests are part of
freia-quality-gates.sh's
gate_integration step (PRD §2.2) and run in CI; they may be skipped
selectively during a fast inner loop via the script's flag surface
(--skip-e2e, --only <gate>), but DONE always requires the full gate
run.
Worked Example
Testing a UserRepository.Save(ctx, user) error method backed by Postgres:
- Start a real Postgres container via
testcontainers in the test's
setup (or reuse the project's docker-compose.dev postgres service),
migrated with the project's actual schema.
- Construct the repository against that real connection — no mock
sql.DB or in-memory fake.
- Happy path: call
Save with a valid user, then read it back via a
direct query and assert the row matches.
- Sad path: call
Save twice with the same unique email and assert
the real unique-constraint violation surfaces as the repository's own
domain error, not a raw driver error leaking through.
- Tear down the container after the test; no shared state leaks into the
next test run.
This test would not catch a real unique-constraint violation if sql.DB
were mocked — the constraint lives in Postgres, not in application code.