behat-extension/doctrine-data-fixtures-extension
Behat extension that loads Doctrine data fixtures before scenarios, making it easy to seed database state for acceptance tests. Configure fixture paths and purgers to keep test data consistent and isolated.
Install with Composer (dev dependency):
composer require --dev behat-extension/doctrine-data-fixtures-extension
Check the README first. This is a small, low-activity package (last release 2019). The README is the canonical source for the exact extension class, context class, and config keys for the version you install. Start by confirming the package’s namespace and required Behat/Doctrine/Symfony versions in composer.json.
Wire it into behat.yml. The typical setup is a Behat extension plus a context that loads fixtures before scenarios. A common shape is:
default:
suites:
default:
contexts:
- BehatExtension\DoctrineDataFixturesExtension\Context\DoctrineDataFixturesContext
- FeatureContext
extensions:
Behat\Symfony2Extension: ~
BehatExtension\DoctrineDataFixturesExtension\Extension:
fixtures:
- features/fixtures
purge: true
Confirm the exact key names (fixtures, purge, cache-related options) in the README for your installed version.
First use case: deterministic database state. Create a simple fixture under features/fixtures/, for example a Doctrine FixtureInterface that inserts two users. Add the context to your suite, run one scenario, and verify the rows exist before your step definitions execute. This is the core value: each scenario starts from a known database state instead of accumulated leftovers.
Verify the integration early. Run a trivial scenario with -vvv, and add a temporary step that counts rows in a table. If the count matches the fixture, the extension is wired correctly before you invest in larger fixture sets.
Suite-level fixture loading. The most common pattern is to configure one or more fixture paths and let the provided context purge and load them before every scenario. Keep fixture sets small and focused; use separate Behat profiles for different fixture directories (e.g., a minimal local profile and a fuller CI profile).
Use Doctrine fixtures normally. Implement Doctrine\Common\DataFixtures\FixtureInterface, use DependentFixtureInterface for ordering, and share objects via getReference(). The extension is essentially a Behat hook around Doctrine’s fixture loader, so existing fixture knowledge transfers directly.
Replace “Given there is a user…” setup steps. Instead of creating data through step definitions, put canonical records in fixtures and have steps assert behavior:
Scenario: Existing user can log in
Given I am on the login page
When I log in as "[email protected]"
Then I should see "Welcome, Alice"
The fixture owns the user; the steps own the interaction.
Use Symfony’s test environment. Run Behat with APP_ENV=test and a dedicated test database. The extension depends on a booted Symfony kernel/Doctrine EntityManager in most setups, so enable Behat\Symfony2Extension and make sure the kernel boots before the fixture hook runs.
Prepare schema outside the scenario. Create or migrate the test schema in CI before Behat runs, then let the extension purge and load per scenario. Purging is not schema creation; it assumes tables exist.
Custom context when you need more control. If your project uses multiple entity managers, custom purge logic, or non-Symfony wiring, copy the small hook pattern into your own context rather than fighting the package:
/** @BeforeScenario */
public function loadFixtures(): void
{
// purge via your own connection logic
// load fixtures via Doctrine\Common\DataFixtures\Loader
}
This is often more maintainable than extending an old package.
CI pattern. Use a disposable database service (MySQL/PostgreSQL container or SQLite file), run migrations/schema creation once, then run Behat. Keep fixture loading fast: avoid huge fixture sets and consider whether purge-per-scenario is necessary for every suite.
Age and maintenance risk. Last release was 2019, with only 20 stars and no dependents. It may not support current PHP, Symfony, Behat, or Doctrine versions. Check Composer constraints before adopting; pin versions and be prepared to fork or replace it with a ~30-line custom Behat hook.
The extension is not a schema tool. It loads data fixtures; it does not create tables or run migrations. Missing tables will surface as purge/load failures, often with confusing SQL errors.
Purge is destructive. Never point it at a shared or production database. Use a dedicated test database and guard the configuration with environment variables. Double-check the purge setting in every profile.
Hook ordering matters. Fixture loading must happen after the Symfony kernel/Doctrine connection is available. If you see “service not found” or “EntityManager is null,” the context is running too early or the Symfony extension is not configured.
Fixture paths are usually project-relative. Globs and directory paths may behave differently than expected. Start with one explicit file, confirm it loads, then expand to a directory.
Caching can mask changes. If the version you use exposes a fixture cache, stale fixtures may be reused after you edit files. Clear Behat/Symfony cache when fixtures appear not to update.
Foreign keys and purge order. Purging tables with foreign-key constraints can fail depending on the database. You may need to disable FK checks, order deletions, or use truncation for your engine.
Transactions and locks. If application code leaves open transactions, purge may block or fail. Ensure the test environment does not reuse a connection with uncommitted state.
Multiple entity managers/connections are a likely limitation. If the package only resolves the default Doctrine manager, scenarios touching a secondary manager need a custom context.
Debug with -vvv and row counts. When fixtures don’t appear, add a temporary step that runs SELECT COUNT(*) against the expected table. That distinguishes “fixture not loaded” from “step definition looking at the wrong database.”
Extension points are limited. You can usually extend or override the provided context’s load method, but with low activity, prefer copying the behavior into your own context. That keeps you in control and avoids being stuck on an unmaintained dependency.
How can I help you explore Laravel packages today?