keepcalculator

06 Numbers and Powers

Automating Drupal Testing: A Step-by-Step Guide

Card No. 06·52178 · Updated · Standard formula, shown below

Automated testing for Drupal websites catches regressions before they reach production, speeds up development, and gives you confidence when updating modules or core. This guide walks you through setting up a testing pipeline using PHPUnit (the framework Drupal core uses) and Drupal’s built-in testing tools. You’ll learn how to write functional tests, run them locally, and integrate them into a CI workflow. No prior testing experience is required, but basic familiarity with the command line and Drupal administration helps.

What You’ll Need

  • A local Drupal site (Drupal 9 or 10) installed via Composer, with a database and web server configured.
  • Composer installed on your machine.
  • PHP 7.4 or higher with the sqlite extension enabled (for testing without a separate database).
  • Drush (optional but recommended) for running tests and managing the site.
  • A code editor and basic knowledge of PHP syntax.

Step-by-Step

  1. Install PHPUnit via Composer. Drupal core already includes PHPUnit as a dev dependency. If it’s missing, run composer require --dev phpunit/phpunit:^9.5 in your project root. Verify with vendor/bin/phpunit --version.
  2. Create a phpunit.xml file. Drupal provides a default configuration at core/phpunit.xml.dist. Copy it to your project root: cp core/phpunit.xml.dist phpunit.xml. Edit it to set the SIMPLETEST_BASE_URL to your local site’s URL (e.g., http://localhost) and SIMPLETEST_DB to a SQLite test database (e.g., sqlite://localhost/tmp/test.sqlite). This tells PHPUnit where to run tests and store test data.
  3. Set up the testing environment. Drupal tests run in an isolated environment. To enable this, create a sites/simpletest directory and make it writable: mkdir -p sites/simpletest && chmod 777 sites/simpletest. Also, ensure your settings.php has $settings['extension_discovery_scan_tests'] = TRUE; so test modules are discovered.
  4. Write a basic functional test. In your custom module (e.g., web/modules/custom/my_module), create a directory tests/src/Functional. Inside, create a PHP class that extends Drupal\Tests\BrowserTestBase. For example, MyModuleTest.php with a method that logs in as an admin and verifies your module’s page loads. Use the @group annotation to categorize the test.
  5. Run the test locally. From your project root, run vendor/bin/phpunit --testsuite=functional --filter MyModuleTest. PHPUnit will spin up a test database, install Drupal, and execute your test. A green result means success.
  6. Add a kernel or unit test (optional). For faster tests that don’t need a full browser, create tests/src/Unit or tests/src/Kernel classes. Unit tests test individual functions; kernel tests test Drupal services with a minimal database. Use these for logic-heavy code.
  7. Set up a Continuous Integration (CI) pipeline. Create a .gitlab-ci.yml or GitHub Actions workflow that runs PHPUnit on every commit. A simple CI job: install dependencies, run phpunit with the same phpunit.xml, and fail if tests fail. This ensures every merge request is tested automatically.
  8. Use Drupal’s testing module (Simpletest) for legacy tests. If you have older tests using the Simpletest API, enable the Simpletest module and run them via drush simpletest-run or the UI at /admin/config/development/testing. New tests should use PHPUnit.
  9. Test with a headless browser (optional). For JavaScript-heavy interactions, use Drupal\Tests\FunctionalJavascript\WebDriverTestBase with ChromeDriver. Install ChromeDriver, set SIMPLETEST_BASE_URL to your site, and run tests with vendor/bin/phpunit --testsuite=functional-javascript.
  10. Document your testing setup. Add a README.md section in your repo explaining how to run tests, so other developers can get started quickly.

Common Mistakes

  • Forgetting to set SIMPLETEST_BASE_URL – tests will fail with connection errors. Always double-check your phpunit.xml.
  • Using the wrong PHPUnit version – Drupal 9 requires PHPUnit 9, Drupal 10 uses PHPUnit 10. Mismatch causes fatal errors.
  • Not clearing the test database – stale test data can cause false failures. Run vendor/bin/phpunit --prune or delete the SQLite file between runs.
  • Ignoring the @group annotation – without groups, you may run all tests, which is slow. Use groups to run only relevant tests.
  • Testing with production settings – never run tests against a live database; always use the isolated test environment.

Tips

  • Start with a simple test that checks a page returns a 200 status. It validates your setup before writing complex tests.
  • Use drush phpunit if you have Drush – it sets environment variables automatically.
  • Run tests in parallel with --parallel to speed up large suites, but be aware of resource usage.
  • Write tests for critical user journeys (login, content creation, checkout) – these give the most value.
  • Keep tests independent: each test should work in isolation. Avoid relying on data from other tests.

Troubleshooting

  • “Error: Class ‘Drupal\Tests\BrowserTestBase’ not found” – ensure you have the correct PHPUnit version and that your test file is in the right namespace and directory.
  • Database connection errors – verify SIMPLETEST_DB is correct and the SQLite extension is enabled. If using MySQL, create a test database and set the DSN accordingly.
  • Tests pass locally but fail in CI – CI often lacks a database or has different PHP settings. Ensure your CI job sets up a database and installs dependencies.
  • “Maximum execution time exceeded” – increase PHP’s max_execution_time in your php.ini or CI environment.
  • Tests hang on JavaScript – ensure ChromeDriver is running and the port is accessible. Update the webdriver.chrome.driver path in your phpunit.xml.

Frequently Asked Questions

Do I need a separate test database?

For local testing, it’s easiest to use SQLite, which creates a file-based database. In CI, you can use MySQL or PostgreSQL. The test runner creates a fresh database schema for each test, so you don’t need to maintain it.

Can I test my custom modules with PHPUnit?

Yes, place tests in your module’s tests/src directory. Drupal’s test discovery will find them as long as your module is enabled and the directory structure is correct.

How do I test forms and user interactions?

Use BrowserTestBase for standard form submissions (e.g., $this->drupalPostForm()). For AJAX or JavaScript interactions, use WebDriverTestBase with a headless browser.

What is the difference between functional and kernel tests?

Functional tests boot the full Drupal environment and simulate HTTP requests, which is slow but realistic. Kernel tests load a subset of services and use a minimal database, making them faster but less comprehensive.

How often should I run tests?

Run them at least before every commit, and automatically in CI on every push. This catches regressions early.

Can I test Drupal core’s functionality?

Yes, Drupal core has its own test suite. You can run it with vendor/bin/phpunit --testsuite=unit (for unit tests) or --testsuite=functional (for functional tests). This helps verify your environment is set up correctly.

Related

Method: the standard formula for this calculation, rounded as each result states. See how the calculators work or report an error.

More cards in this drawer

The whole Numbers and Powers drawer →