Now liveThe Skillselion MCP - thousands of ranked skills, loaded into your agent mid-task. No install.Get it →
netresearch avatar

Oro Functional Testing

  • 2 installs
  • 2 repo stars
  • Updated July 22, 2026
  • netresearch/orocommerce-skill

Writes PHPUnit functional tests for OroCommerce 6.1 with WebTestCase: controllers, REST API, commands, datagrids, ACL flows, fixtures, and transactional isolation annotations.

About

Covers OroCommerce 6.1 functional testing on top of WebTestCase, including initClient, fixture loading, isolation annotations, and HTML/JSON/grid assertions against a real database. A developer uses it when testing controllers, APIs, commands, or ACL rules in an Oro bundle.

  • Canonical WebTestCase with initClient, loadFixtures, and dbIsolationPerTest
  • Basic vs API auth headers and datagrid/JSON assertion helpers

Oro Functional Testing by the numbers

  • 2 all-time installs (skills.sh)
  • +1 installs in the week ending Aug 4, 2026 (Skillselion tracking)
  • Ranked #1,683 of 2,153 Testing & QA skills by installs in the Skillselion catalog
  • Data as of Aug 4, 2026 (Skillselion catalog sync)
npx skills add https://github.com/netresearch/orocommerce-skill --skill oro-functional-testing

Add your badge

Show developers this skill is listed on Skillselion. Paste this into your README.

Listed on Skillselion
Installs2
repo stars2
Last updatedJuly 22, 2026
Repositorynetresearch/orocommerce-skill

What it does

Writes PHPUnit functional tests for OroCommerce 6.1 with WebTestCase: controllers, REST API, commands, datagrids, ACL flows, fixtures, and transactional isolation annotations.

Files

SKILL.mdMarkdownGitHub ↗

OroCommerce v6.1 Functional Testing (PHPUnit)

Functional tests exercise real controllers, services, commands, APIs, and ACL rules against a real database. Oro's WebTestCase boots the kernel, manages transactional isolation, loads fixtures deterministically, and layers HTTP/grid/JSON helpers on top of Symfony's BrowserKit client.

Canonical WebTestCase

This is the reference pattern combining initClient, fixtures, isolation annotations, and HTML assertions:

<?php
namespace Acme\Bundle\DemoBundle\Tests\Functional\Controller;

use Acme\Bundle\DemoBundle\Entity\Document;
use Acme\Bundle\DemoBundle\Tests\Functional\DataFixtures\LoadDocumentData;
use Oro\Bundle\TestFrameworkBundle\Test\WebTestCase;

/**
 * @dbIsolationPerTest
 * @outputBuffering enabled
 */
class DocumentControllerTest extends WebTestCase
{
    protected function setUp(): void
    {
        $this->initClient([], $this->generateBasicAuthHeader());
        $this->loadFixtures([LoadDocumentData::class]);
    }

    public function testIndex(): void
    {
        $crawler = $this->client->request('GET', $this->getUrl('acme_demo_document_index'));

        $result = $this->client->getResponse();
        $this->assertHtmlResponseStatusCodeEquals($result, 200);
        $this->assertStringContainsString('Documents', $crawler->html());
    }

    public function testView(): void
    {
        /** @var Document $document */
        $document = $this->getReference('document.first');
        $this->client->request('GET', $this->getUrl('acme_demo_document_view', ['id' => $document->getId()]));

        $this->assertHtmlResponseStatusCodeEquals($this->client->getResponse(), 200);
    }
}

initClient(array $kernelOptions = [], array $serverOptions = []) boots the kernel; pass generateBasicAuthHeader($user, $pass) to authenticate (defaults: admin@example.com / admin). loadFixtures(array $fixtures, bool $force = false) loads once per test case; dependencies resolve transitively via DependentFixtureInterface. getReference('name') retrieves entities registered from fixtures. See fixtures.md for entity manager clearing behavior and InitialFixtureInterface.

WebTestCase Helpers

WebTestCase provides these instance helpers; memorize the signatures to avoid guessing:

  • initClient(array $kernelOptions = [], array $serverOptions = []) — boot kernel, optionally authenticate
  • generateBasicAuthHeader(string $username = 'admin@example.com', string $password = 'admin') — HTML-form basic auth header
  • generateApiAuthHeader(string $username) — REST API auth header (no password needed; test framework issues a token)
  • loadFixtures(array $fixtures, bool $force = false) — load PHP or YAML fixtures (@BundleName/path/to/file.yml)
  • getReference(string $name) — fetch an entity registered by a fixture
  • getContainer() — DI container for pulling services
  • runCommand(string $commandName, array $params) — execute a console command, returns output string
  • requestGrid(string $gridName, array $gridParams) — request a datagrid JSON response (called on $this->client)
  • getJsonResponseContent(Response $response, int $expectedCode) — assert status + decode JSON
  • assertHtmlResponseStatusCodeEquals(Response $response, int $expectedCode) — asserts status, dumps body on failure
  • assertJsonResponseStatusCodeEquals(Response $response, int $expectedCode) — same for JSON responses
  • getUrl(string $routeName, array $routeParams = []) — resolve a Symfony route to a URL

Isolation Annotations

  • @dbIsolationPerTest — wraps each test method in a transaction that rolls back on completion. Without it, every method in the class shares one transaction and state bleeds between tests.
  • @outputBuffering enabled — required on WebTestCase subclasses so controller output is captured correctly. PHPUnit strict output mode otherwise fails on any echo inside request handling.
  • @depends testMethodName — inherits both fixtures and state from the dependent test. Use sparingly for sequential scenarios (create -> update -> delete) where full isolation would defeat the point of the test.

Controller, API, Command, Grid

The kernel is reused across all test types; what differs is the helper and the auth header:

// HTML controller
$this->initClient([], $this->generateBasicAuthHeader());
$this->client->request('GET', $this->getUrl('route_name', ['id' => 1]));
$this->assertHtmlResponseStatusCodeEquals($this->client->getResponse(), 200);

// REST API (back-office)
$this->initClient([], $this->generateApiAuthHeader('admin@example.com'));
$this->client->request('GET', $this->getUrl('oro_api_get_users'));
$result = $this->getJsonResponseContent($this->client->getResponse(), 200);

// Console command — no auth header, still needs initClient()
$output = $this->runCommand('oro:search:reindex', ['--class' => 'OroUserBundle:User']);
$this->assertStringContainsString('Reindex finished', $output);

// Datagrid
$response = $this->client->requestGrid('users-grid', ['users-grid[_filter][username][value]' => 'admin']);
$result = $this->getJsonResponseContent($response, 200);

See grid-testing.md for filter bracket notation and acl-patterns.md for 403 assertion flows.

Test Environment Installation

Install the test env via php bin/console oro:install --env=test. CLI flags like `--user-email=...` are silently ignored in test env — functional tests rely on exact values, so install parameters must come from oro_test_framework.install_options in config/config.yml. See install-options.md for every field.

Test-specific environment variables live in .env-app.test.local:

ORO_DB_DSN=postgresql://root@127.0.0.1/crm_test
ORO_MAILER_DSN=smtp://127.0.0.1

Running Tests

# Functional suite only
docker compose run --rm toolbox bin/phpunit -c ./ --testsuite=functional

# Unit suite only
docker compose run --rm toolbox bin/phpunit -c ./ --testsuite=unit

Never run both suites in one PHPUnit invocation. Mock objects registered by unit tests interfere with kernel boot and service resolution in functional tests. This is Oro's canonical warning; it typically surfaces as baffling service-not-found or class-not-found errors deep inside seemingly unrelated tests.

Key Pitfalls

1. Running unit + functional suites together — mock objects from unit tests interfere with functional test execution. Always separate runs (--testsuite=unit and --testsuite=functional). 2. Forgetting `@dbIsolationPerTest` — all test methods in the class share one transaction, state bleeds between tests, and failures become order-dependent and hard to reproduce. 3. Passing `--user-email=...` CLI flags to `oro:install --env=test` — silently ignored. Test env rejects install command options; the only supported path is oro_test_framework.install_options YAML. 4. Assuming fixtures share entity manager state — the entity manager is cleared after each fixture by default. Entities referenced during fixture A are detached by the time fixture B runs. Implement InitialFixtureInterface on fixtures whose entities must survive. 5. Using bundle aliases for entity FQCNs in tests ('OroProductBundle:Product') — deprecated in Doctrine; use Product::class everywhere.

See Also

  • install-options.md — Full oro_test_framework.install_options block, every field, and the CLI-flags-ignored gotcha
  • fixtures.md — PHP/YAML fixtures, DependentFixtureInterface, InitialFixtureInterface, EM clearing, built-in Load* fixtures, references
  • acl-patterns.md — HTML 403 vs JSON 403, generateBasicAuthHeader vs generateApiAuthHeader, limited-user setup, grid ACL
  • grid-testing.mdrequestGrid signature, filter bracket notation, getJsonResponseContent, row extraction
  • v6.1.md — Symfony 6.4 base, env file naming, unit-vs-functional separation warning
  • v7.0.md — v7.0 deltas (placeholder)

Related skills

This week in AI coding

Five minutes, every Monday - the tools, releases and tactics for developers.

unsubscribe anytime.