Weave Code
Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Functional Test Bundle Laravel Package

i22/functional-test-bundle

i22/functional-test-bundle provides functional testing helpers for PHP applications, with utilities to bootstrap test environments and assert end-to-end behavior. It aims to reduce boilerplate when adding reliable functional coverage to your test suite.

View on GitHub
Deep Wiki
Context7

Getting Started

Reality check first. This bundle was last released in August 2019 (v0.x era, Symfony 4.x timeframe), has 0 stars and 0 dependents. Treat it as a small piece of glue code rather than a maintained dependency — you are effectively adopting it and its transitive constraints (hautelook/alice-bundle + nelmio/alice versions of that era) into your test suite. Read the source before installing; it is small enough to vendor or reimplement.

Minimal steps

  1. Install alongside the Alice stack it wraps:

    composer require --dev i22/functional-test-bundle hautelook/alice-bundle
    

    Pin hautelook/alice-bundle and nelmio/alice to versions compatible with your PHP/Symfony. On PHP 8.1+ / Symfony 6+, expect resolver conflicts and be prepared to fork.

  2. Register the bundle in config/bundles.php (Symfony 4 style; on Symfony 5+ bundles are no longer auto-registered by Flex, so this is manual):

    return [
        // ...
        I22\FunctionalTestBundle\I22FunctionalTestBundle::class => ['test' => true],
    ];
    

    The ['test' => true] environment flag is the important part — it keeps test-only wiring out of dev/prod kernels.

  3. Point the bundle/Alice at your fixture directory. The bundle's config typically extends the Alice configuration with a fixtures path and a Doctrine connection name (check the bundle's DependencyInjection/Configuration.php for the exact keys — they are the authoritative documentation here):

    # config/packages/test/i22_functional_test.yaml
    i22_functional_test:
        fixtures_path: '%kernel.project_dir%/tests/fixtures'
        # connection: default
    
  4. Where to look first: vendor/i22/functional-test-bundle/src/ — specifically the base test case class and any trait it ships. That base class is the entire product: it hands you a booted kernel, a client, and a fixture-loading method. Everything below assumes you extend it.

  5. First use case — a controller/endpoint smoke test:

    // tests/Functional/HomepageTest.php
    use I22\FunctionalTestBundle\Test\WebTestCase; // verify exact FQCN in vendor/
    
    class HomepageTest extends WebTestCase
    {
        protected function setUp(): void
        {
            parent::setUp();
            $this->loadFixtures(['users.yaml', 'articles.yaml']);
        }
    
        public function testHomepageShowsLatestArticle(): void
        {
            $client = static::createClient();
            $client->request('GET', '/');
    
            $this->assertResponseIsSuccessful();
            $this->assertSelectorTextContains('h1', 'Latest');
        }
    }
    

    If that green bar appears with a populated database, the bundle is doing its job: no manual doctrine:fixtures:load, no hand-rolled setUp() boilerplate.

Implementation Patterns

One fixture file per test concern, not per entity. Alice YAML files are cheap; loading three focused files in setUp() beats one giant fixtures.yaml with dozens of conditional references. Because Alice assigns object references by file-local key, small files also keep reference names (user_admin, article_draft) predictable across tests.

Load in setUp(), retrieve by reference, assert against real objects. The productive loop is: load fixtures → grab the object you need from the container's EntityManager (or the bundle's fixture-reference helper, if it exposes one) → drive the HTTP client → assert on both response and persisted state.

protected function setUp(): void
{
    parent::setUp();
    $this->loadFixtures(['users.yaml']);
}

public function testProfileUpdatePersists(): void
{
    $user = $this->getRepository(User::class)->findOneBy(['email' => '[email protected]']);
    self::createClient()->request('POST', '/profile', ['name' => 'Jane D.']);

    $this->assertResponseIsSuccessful();
    $this->getEntityManager()->refresh($user);
    self::assertSame('Jane D.', $user->getName());
}

Asserting on the refreshed entity, not just the status code, is what converts these from smoke tests into regression tests.

Isolation strategy is the real decision. Two viable models:

  • Rollback per test — wrap each test in a DB transaction (beginTransaction() in setUp(), rollback in tearDown()). Fast, but breaks on any DDL or on code that commits internally (e.g. message handlers, EntityManager::flush() inside a service that commits its own transaction, TRUNCATE-based fixtures).
  • Schema rebuild + load — drop/recreate the test schema and reload fixtures per test class. Slower but robust. With fixtures loaded in setUp() and a static schema cache keyed by class, this stays tolerable.

Pick rollback for read-heavy CRUD endpoints, rebuild for anything touching schema, migrations, or async flows. Do not mix the two in one suite — silent data leakage between tests is the usual outcome.

Fixtures compose with data providers. A provider that yields ['role' => 'ROLE_ADMIN', 'expectedStatus' => 200] plus a single parametrised setUp() that adapts the fixture set gives you broad authorization coverage with very little code. Guard against Alice's per-process caching here — see Gotchas.

Use the bundle's client for end-to-end, not for unit concerns. These tests boot the full kernel: they are the slowest thing in your suite. Keep business-rule coverage in unit tests, and reserve the functional layer for routing, serialization, security voters, Doctrine mappings, and form validation — the things that only fail when wired together.

CI wiring. Run against the same engine as production if you rely on constraint/transaction semantics (SQLite in practice hides FK and locking bugs). For paratest/parallel CI, either give each worker its own database or its own SQLite file — a shared var/test.db will produce flaky, order-dependent failures.

Gotchas and Tips

The staleness is the headline gotcha. No release since 2019 means: no Symfony 5/6/7 support guarantees, no PHP 8 fixes (typed property and nullable-parameter deprecations are common in code of this vintage), and hautelook/alice-bundle v3 removed/changed APIs the bundle may reference. Before adopting, check composer.json constraints against your platform; if they conflict, fork the repo (it is small) or lift the base test case into tests/Support/ and drop the dependency. For a new project, hautelook/alice-bundle alone or zenstruck/foundry is the lower-risk path.

Zero dependents is a signal, not a verdict. It means nobody is filing the bugs you will hit. Budget time to read the source; assume you are the maintainer.

Alice loads each fixture file once per process. If the bundle caches loaded fixture sets statically, a second test in the same PHP process may see stale references or skip the reload entirely — the classic symptom is "passes alone, fails in the suite" or vice versa. If you hit it, force a reload in tearDown()/setUp() or disable the cache. This is the single most common source of confusion with Alice-based bundles.

Kernel reboots and static state. static::createClient() boots and shuts down the kernel per test; anything cached statically in your app (compiled container, Doctrine metadata, your own service singletons) survives. If a test mutates a service that other tests read, shut the kernel down explicitly or @runInSeparateProcess the offender.

Transaction rollback silently swallows writes. If your code calls $em->getConnection()->commit() or a listener does, the rollback in tearDown() no longer undoes the data. Symptom: leakage into later tests that only shows up when the suite is reordered. --order-by=random (PHPUnit) is the cheapest detector you have; run it in CI.

SQLite in-memory is per-connection. If the bundle opens its own connection for fixture loading and the kernel opens another, schema and data vanish. Use a file-backed SQLite test DB or point both at the same connection name in config.

Fixture reference names are file-scoped in practice. Two files each defining user_admin will not necessarily collide the way you expect — but relying on cross-file references is fragile. Prefix names per aggregate (blog_article_1, shop_order_1).

Debugging tips. When fixtures fail to load, the error is usually a Doctrine mapping problem disguised as an Alice error: run bin/console doctrine:schema:validate --env=test first, then narrow to the single YAML file. Dump the loaded reference map (or just dump() the repository counts in setUp()) to confirm the data actually landed. Enable the Doctrine SQL logger in config/packages/test/doctrine.yaml when a request returns 500 for no apparent reason — half the time it is a missing column the fixtures never populated.

Extension points worth knowing. Override the bundle's fixture-loading method in your own AbstractFunctionalTestCase to add project defaults (locale, authenticated user helper, schema cache). Register custom Alice providers (nelmio/alice providers) for domain-specific values — money, slugs, enum states — rather than duplicating faker incantations across YAML. Keep that base class thin; it is the one file you will actually maintain if you fork.

Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
jinas/dhivatar
store-doc/laravel-storage-driver
plus-it/laravel-translation-manager
diephp/perhaps
diephp/telegraph
osmaviation/spreadsheet
microsoft/fluentui-system-icons
mmccook/php-json-canonicalization-scheme
middlewares/firewall
qubiqx/montapacking
nyoncode/laravel-package-console
pnscripts/filament-broadquill-lite
pnscripts/laravel-sentfold-lite
vleap/mx-sdk-laravel-internal
twidpay/utils
htetmyathlaing/scout-elasticsearch-driver
artisan-toolbox/front-awesome
ls/client-assistant
users-au/laravel-client
cgv/localized-resource