macpaw/behat-redis-context
A Behat context for Redis-backed acceptance tests: clean or flush test databases between scenarios, seed and inspect keys, and keep feature suites isolated, repeatable, and free of stale test data.
This is a Symfony bundle that ships a Behat context for asserting against Redis. It is a test-time dependency only, so install it as a dev requirement:
composer require --dev macpaw/behat-redis-context
1. Check the version you get. v3.0.0 is a dependency-only major release: the maintainers widened the constraint set to support the latest PHP/Behat/Symfony releases (changelog entry dated 2026-03-30), which is why the major version was bumped even though no step definitions changed. Before upgrading an existing suite, run composer update macpaw/behat-redis-context --dry-run -v and read the resolved versions; if your app is still on an older PHP or Behat line, Composer will hold you back — pin ^2.0 explicitly rather than letting a composer update drag the whole test toolchain forward mid-sprint.
2. Register the bundle. On Symfony Flex projects the bundle should be auto-discovered. On older apps add it to config/bundles.php:
MacPaw\BehatRedisContext\BehatRedisContextBundle::class => ['test' => true],
3. Wire it into Behat. In behat.yml, enable the Symfony extension and add the context to your suite:
default:
extensions:
Behat\Symfony2Extension:
kernel:
env: test
debug: true
suites:
default:
contexts:
- MacPaw\BehatRedisContext\Context\RedisContext
4. Where to look first. Open vendor/macpaw/behat-redis-context/src/ and read the context class and its step annotations — that is the authoritative list of available steps, not the README (the README's install.md was revised in v3.0.0, but the step list still lags the code). Also check for a DependencyInjection/Configuration.php to see what connection options the bundle accepts (host, port, database index, key prefix, client class). The repo now also ships an AGENTS.md in v3.0.0 — it is a short architecture map and is genuinely the fastest orientation document if you plan to patch or extend the package. Then run:
vendor/bin/behat --definitions l
to see the resolved step text and regexes available to your features.
5. First use case. The canonical pattern: seed a key with a Given step, exercise the app (HTTP request, console command, or service call), then assert the resulting Redis state with a Then step. This is most valuable for code paths that write directly to Redis — rate limiters, queues, session stores, cache warmers, locks — where a database assertion cannot prove anything.
Scenario isolation via hooks. The single most important pattern is cleaning the keyspace between scenarios. Use a @BeforeScenario / @AfterScenario hook (either inside the shipped context or your own) to delete only the keys your suite owns. Prefer a dedicated database index for tests (e.g. db: 15) plus a per-suite prefix, and never rely on FLUSHALL if the Redis instance is shared with a dev cache or another CI job.
Seed → act → assert. Structure features so the Given steps set up state, the When step drives your application, and the Then steps inspect Redis. For example:
Scenario: Lock is released after the command finishes
Given redis key "lock:report:42" does not exist
When I run the "report:generate 42" command
Then redis key "lock:report:42" should not exist
Reuse the client from your own contexts. If you need a custom assertion the bundle does not cover (sorted-set scores, hash field counts, stream entries), extend the shipped context or inject the same Redis client and write your own step definitions. This keeps a single connection and a single configuration source rather than a second hand-rolled Predis instance in features/bootstrap.
Compose with API/Mink contexts. Register the Redis context alongside your HTTP context in the same suite so a single scenario can drive a request and then inspect the resulting keys. Keep step wording distinct to avoid regex collisions (see Gotchas).
Scenario Outline for key matrices. When verifying that several keys are written or several TTLs are set, use an Examples table rather than repeating near-identical scenarios. It is much cheaper to extend than a wall of copied steps.
Config-driven connection. Keep host/port/database in behat.yml bundle config or environment variables (REDIS_HOST, REDIS_PORT, REDIS_DB) so CI can point at a service container while developers point at localhost. Avoid hardcoding a database index in a step definition.
Pin the toolchain when you upgrade. Because v3.0.0 only moves constraints, the practical upgrade risk lives in the transitive resolution, not in the package's own code. Upgrade the package and Behat/Symfony together, run --definitions l before and after, and diff the output — that is a cheap regression check for a release that ships no new steps.
services: redis, or a Docker Compose dependency) and health-check it before running Behat, otherwise you get opaque connection-refused failures mid-suite.composer update may pull newer Behat and Symfony test dependencies at the same time. If a suite breaks after the bump, check composer show --latest for Behat/behat/symfony2-extension first — the failure is far more likely to be an upstream behavioural change than anything in this package.igbinary or lzf compression, values written by the app will be unreadable by the context (and vice versa). Align the client and serializer config, or assert on existence and type rather than raw values.SCAN/DEL rather than FLUSHDB, or you will silently wipe cache entries the rest of the test run depends on.behat --definitions l and look for overlapping patterns when you add custom steps.features/bootstrap may not be autoloadable by FQCN. Either register the namespace under autoload-dev in composer.json or reference the class by its full path. The shipped context lives under the vendor namespace and is fine.> 0 and < some upper bound, or assert the key disappears after a controlled sleep only when the TTL is sub-second. Time-based keys are the most common cause of intermittent green/red flips.test only (['test' => true]) so it never pollutes production container compilation.redis-cli -n <db> monitor in a second terminal while behat --stop-on-failure executes — you see the exact commands issued and can tell whether the app failed to write or the assertion targeted the wrong prefix. KEYS prefix:* after a failure confirms what actually landed.behat.yml rather than patching vendor code; that survives composer update.composer dev-checks (validate + PHPStan at max level + PHPUnit + PHP_CodeSniffer with Slevomat rules). v3.0.0 cleared the remaining PHPStan errors, so the static-analysis gate is now clean at max level — keep it that way if you send a patch, and run composer code-style before opening a PR. The package targets PHP 8.2; the new AGENTS.md describes the layout and conventions and is a good first read whether you are using an AI assistant or not.How can I help you explore Laravel packages today?