Skip to content

Parallel + container-backed test infra: paratest + testcontainers-php #129

Description

@tonydspaniard

Motivation

Two gaps in the current testing story:

  1. Ext/DB-backed tests are CI-only. Tests that need ext-mongodb, ext-redis, ext-memcached, Beanstalk (pda/pheanstalk), or a live database for the Cycle ORM bridge (univeros/persistence) cannot run on a typical dev machine without those extensions/services installed, so they only really execute in CI. That makes a whole class of integration code slow to iterate on and easy to break locally without noticing (e.g. the MongoSessionHandlerTest tearDown() quirk).
  2. Suite wall-clock grows. As packages land (the suite is already 200+ tests across 28 packages) a single-process PHPUnit run gets slower, especially once container-backed integration tests are added.

These two tools are complementary and address both:

  • testcontainers-php — spin up throwaway Docker containers (Mongo, Redis, Memcached, Beanstalk, MySQL/Postgres) per test run, so the ext/DB integration tests run identically locally and in CI, with no global service install.
  • paratest — parallelize the PHPUnit 11 suite to keep it fast as it grows.

Proposed scope

  • Add brianium/paratest (dev) and wire a composer test:par script alongside the existing composer test. Confirm it cooperates with the Altair\TestReporter PHPUnit extension (JSON report) and coverage.
  • Add a testcontainers-php dev dependency and a small base TestCase/trait that lazily boots the container a given integration test needs, skipping gracefully when Docker is unavailable (so composer test without Docker still works, like today).
  • Port the currently CI-only ext/DB tests to container-backed fixtures: Session (Mongo/Predis/PDO handlers), Cache (Redis/Memcached/Predis storage), Persistence (Cycle against a real DB), Messaging (Beanstalk transport).
  • Decide isolation strategy for parallel + shared containers (see risks) and document it.
  • Update CI (.github/workflows/ci.yml) to use the container-backed path and (optionally) paratest, removing the bespoke service setup.
  • Docs: a short "running the integration suite" section.

Risks / open questions

  • Isolation under parallelism is the crux. paratest runs N worker processes; if they share one Redis/DB container they will contaminate each other. Options: a container instance per worker (TEST_TOKEN-keyed), or one container with per-test isolation (unique DB name / Redis keyspace / Mongo database per test). Needs a decision before porting tests.
  • Docker becomes a dev/CI prerequisite for the integration suite. The unit suite must stay Docker-free and fast (graceful skip when Docker is absent).
  • Coverage + paratest + the TestReporter extension interaction needs verifying (merging per-process coverage; the golden-file determinism of build/test-results.json).
  • Container boot time vs. CI minutes — measure before/after.

Related

  • Pairs naturally with univeros/doctor's database_reachable / extensions_loaded checks — a container-backed dev loop makes those probes pass locally instead of skipping.
  • Separate initiative from the introspection/suggest tooling; this is purely test infrastructure.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions