Skip to main content
Oro applications come with many configurable features. To ensure everything works as expected regardless of configuration combinations, Oro developers write automated tests. Since the application has many features, automated testing is a big part of the development workflow. From the start, the project has used unit and functional tests to validate the application architecture and programming APIs. Additionally, Behat Behavior-Driven Development tests simulate actual user interactions in a real web browser using the Gherkin domain-specific language.

Test types

End-to-End Tests

High-level user-flow tests that exercise the full application stack from the browser.

Integration Tests (Behat)

BDD-style tests written in Gherkin that simulate user interactions in a real browser.

Functional Tests (PHPUnit)

PHPUnit-based tests that verify the integration of services, repositories, controllers, and commands.

k6 Performance Tests

Load and performance tests written with k6 to identify bottlenecks under realistic traffic.

Debug Behat Tests

Techniques and tools for debugging failing Behat scenarios.

Functional tests (PHPUnit)

Functional tests check the integration of different application layers. Write them for:
  • Controllers — verify request/response cycles and form submissions
  • Commands — verify console command output and side effects
  • Repositories — verify database queries return expected results
  • Services — verify business logic through real container services

Test environment setup

1

Create a test database

Create a separate database (e.g., add a _test suffix to the database name).
2

Configure environment variables

Set database and mail server settings in .env-app.test.local:
ORO_DB_DSN=postgresql://[email protected]/crm_test
ORO_MAILER_DSN=smtp://127.0.0.1
3

Install the application in test mode

php bin/console oro:install --env=test
Test environments do not support all install command options. Adjust oro_test_framework.install_options in config/config.yml if needed.
4

Run functional tests

php bin/phpunit -c ./ --testsuite=functional
Do not run unit and functional tests together in the same run. Unit tests create mock objects that interfere with functional test execution.

Writing a functional test

Extend Oro\Bundle\TestFrameworkBundle\Test\WebTestCase and initialize the client in setUp():
namespace Oro\Bundle\FooBundle\Tests\Functional;

use Oro\Bundle\TestFrameworkBundle\Test\WebTestCase;

/**
 * @dbIsolationPerTest
 */
class FooBarTest extends WebTestCase
{
    protected function setUp()
    {
        $this->initClient([], $this->generateBasicAuthHeader());
        $this->loadFixtures([
            'Oro\Bundle\FooBarBundle\Tests\Functional\DataFixtures\LoadFooData',
        ]);
    }

    // test methods...
}
The @dbIsolationPerTest annotation wraps each test method in a transaction that is rolled back on completion, keeping the database clean between tests.

Loading fixtures

$this->loadFixtures([
    'Oro\Bundle\FooBarBundle\Tests\Functional\DataFixtures\LoadFooData',
    '@OroFooBarBundle/Tests/Functional/DataFixtures/bar_data.yml',
]);
A fixture must either:
  • Implement Doctrine\Common\DataFixtures\FixtureInterface, or
  • Be a path to a nelmio/alice YAML file.

Testing a controller

public function testCreate()
{
    $crawler = $this->client->request('GET', $this->getUrl('orocrm_task_create'));

    $form = $crawler->selectButton('Save and Close')->form();
    $form['orocrm_task[subject]'] = 'New task';
    $form['orocrm_task[dueDate]'] = '2014-03-04T20:00:00+0000';

    $this->client->followRedirects(true);
    $crawler = $this->client->submit($form);
    $result = $this->client->getResponse();

    $this->assertHtmlResponseStatusCodeEquals($result, 200);
    $this->assertContains('Task saved', $crawler->html());
}

Testing a command

Use runCommand() to execute console commands and assert output:
public function testCommand($commandName, array $params, $expectedContent)
{
    $result = $this->runCommand($commandName, $params);
    $this->assertContains($expectedContent, $result);
}

Testing ACL in a controller

Verify that a user without sufficient permissions receives a 403 response:
$this->client->request(
    'GET',
    $this->getUrl('oro_user_index'),
    [],
    [],
    $this->generateBasicAuthHeader(LoadUserData::USER_NAME, LoadUserData::USER_PASSWORD)
);
$result = $this->client->getResponse();
$this->assertHtmlResponseStatusCodeEquals($result, 403);

Build docs developers (and LLMs) love