PHPUnit
Vortex uses PHPUnit as a framework for unit, kernel, functional and functional JavaScript testing. PHPUnit tests verify that individual components work correctly in isolation and when integrated with Drupal's systems.
Vortex provides full PHPUnit support, including configuration in phpunit.xml
based on Drupal core's core/phpunit.xml.dist to allow customizing the test
suite per project.
Usage
- Ahoy
- Docker Compose
# Run all PHPUnit tests (all suites)
ahoy test
# Run only Unit tests
ahoy test-unit
# Run only Kernel tests
ahoy test-kernel
# Run only Functional tests
ahoy test-functional
# Run only Functional JavaScript tests
ahoy test-functional-javascript
# Run specific test file
ahoy test tests/phpunit/ExampleTest.php
# Run tests with filter
ahoy test -- --filter=testMethodName
# Run tests tagged with a `@group group_name` annotation
ahoy test -- --group=group_name
# Run all PHPUnit tests (all suites)
docker compose exec cli vendor/bin/phpunit
# Run only Unit tests
docker compose exec cli vendor/bin/phpunit --testsuite=unit
# Run only Kernel tests
docker compose exec cli vendor/bin/phpunit --testsuite=kernel
# Run only Functional tests
docker compose exec cli vendor/bin/phpunit --testsuite=functional
# Run only Functional JavaScript tests
docker compose exec cli vendor/bin/phpunit --testsuite=functional-javascript
# Run specific test file
docker compose exec cli vendor/bin/phpunit tests/phpunit/ExampleTest.php
# Run tests with filter
docker compose exec cli vendor/bin/phpunit --filter=testMethodName
# Run tests tagged with a `@group group_name` annotation
docker compose exec cli vendor/bin/phpunit --group=group_name
Writing tests
Skipping tests
Add a @group skipped annotation to a test class or method to exclude it from
the test run - phpunit.xml excludes the skipped group by default:
/**
* @group skipped
*/
public function testSomethingToSkip(): void {
// This test will be skipped
}
Boilerplate
Vortex provides unit, kernel, functional and functional JavaScript tests boilerplate for custom modules, themes and scripts.
These boilerplate tests run in the continuous integration pipeline when you install Vortex and can be used as a starting point for writing your own.
Drupal settings tests
Vortex provides Drupal settings tests to check that Drupal settings are correct based on the environment type the site is running: with the number of custom modules multiplied by the number of environment types, it is easy to miss certain settings which may lead to unexpected issues when deploying a project to a different environment.
They are intended to be used in your site and kept up-to-date with the
changes made to the settings.php file.
Continuous integration pipeline configuration tests
Vortex provides CircleCI configuration tests to check that the continuous integration configuration is correct. They are intended to be used in your site and kept up-to-date with the continuous integration configuration.
For example, there are tests for regular expressions used to filter the branches and tags before they are deployed to the hosting environment.
Project conventions
For project-specific test writing conventions (test class structure, base classes,
data providers, test data conventions), see your project's docs/testing.md file.
The docs/testing.md file is scaffolded when you install Vortex and should
be maintained by your project team to document agreed-upon testing practices.
Configuration
All global configuration takes place in the phpunit.xml
file in the project root. It configures:
- Test suite directories and naming patterns
- Bootstrap file for Drupal integration
- Environment variables for test execution
- Code coverage settings
By default, PHPUnit will run tests for custom modules and themes, Drupal settings, and the shipped CircleCI configuration test.
Test suites
PHPUnit tests are organized into test suites defined in phpunit.xml:
- unit - fast tests of isolated PHP classes without a Drupal bootstrap
- kernel - tests with a partial Drupal bootstrap (database and core services)
- functional - tests with a full Drupal bootstrap and browser simulation
- functional-javascript - tests with a full Drupal bootstrap and a real browser (Chrome via Selenium) for JavaScript interactions
The recommended way of adding test targets is via test suites:
<testsuite name="unit">
<directory>my/custom/dir/*/tests</directory>
</testsuite>
Chrome session flags
Functional JavaScript tests use a Chrome browser running in the
selenium/standalone-chromium
container. The following flags are passed via MINK_DRIVER_ARGS_WEBDRIVER
in phpunit.xml to ensure stable and deterministic test execution:
| Flag | Purpose |
|---|---|
--disable-extensions | Prevents interference from browser extensions |
--disable-popup-blocking | Allows tests to open popups without being blocked |
--disable-translate | Prevents the translation bar from appearing on non-English pages |
--force-prefers-reduced-motion | Disables CSS animations and transitions for test stability |
--test-type | Suppresses error dialogs and crash recovery prompts |
--window-size=1920,1080 | Sets a deterministic viewport size for consistent screenshots |
The w3c: true option is required for compatibility with Selenium 4.
Bootstrap
The custom tests/phpunit/bootstrap.php
file runs before tests to:
- Set
BROWSERTEST_OUTPUT_BASE_URLfrom theLOCALDEV_URLenvironment variable so that HTML output links are accessible from the host machine. - Create the
web/sites/simpletest/browser_outputdirectory required by theHtmlOutputLoggerextension before it initializes (see Drupal core issue #2992069).
Reports
PHPUnit writes a JUnit XML report to .logs/test_results/phpunit/phpunit.xml.
Coverage
PHPUnit is configured to generate code coverage reports. The reports are stored
in .logs/coverage/phpunit/cobertura.xml
as Cobertura XML, suitable for
automated coverage assessment, and in .logs/coverage/phpunit/.coverage-html as
an HTML coverage report, useful for visual report assessment during test
development.
Ignoring lines from coverage
Sometimes it is necessary to ignore lines from coverage. For example, when testing a module that uses a third-party library, it is not necessary to test the library itself.
To ignore a method from coverage, add @codeCoverageIgnore annotation to the
method docblock.
/**
* @codeCoverageIgnore
*/
public function myMethod() {
// ...
}
To ignore a line from coverage, add @codeCoverageIgnoreStart and
@codeCoverageIgnoreEnd annotations before the first and after the last line.
// @codeCoverageIgnoreStart
$a = 1;
$b = 2;
// @codeCoverageIgnoreEnd
Continuous integration
In the continuous integration pipeline, PHPUnit runs on the first container only, see Test parallelism. The pipeline runs tests with coverage by default and stores the coverage reports as artifacts, and collects the JUnit report to track test performance and stability.
Coverage threshold
CI enforces a minimum coverage threshold. If coverage falls below the threshold,
the build fails. Set VORTEX_CI_CODE_COVERAGE_THRESHOLD to configure the
minimum percentage (default: 90).
Coverage reports are posted as PR comments automatically. Each new report
replaces the previous one - older comments are minimized to keep the PR
timeline clean. The comment includes a header indicating the CI source
(GitHub Actions or CircleCI). Set VORTEX_CI_CODE_COVERAGE_PR_COMMENT_SKIP to
1 to disable.
Ignoring failures
Set the VORTEX_CI_PHPUNIT_IGNORE_FAILURE environment variable to 1 to ignore
failures. The tool still runs and reports violations. See
Ignore tool failures.