Dries Buytaert

PHPUnit tests for Drupal

This page is part of my digital garden. It is more like a notebook entry than a polished blog post. It's a space where I document learnings primarily for my own reference, yet share them in case they benefit others. Unlike my blog posts, these pages are works-in-progress and updated over time. Like tending to a real garden, I periodically refine its content. I welcome suggestions for improvements at dries@buytaert.net.

Writing tests can be hard. The key is to get started. When I start work on a new Drupal module, I like to start off by adding a very simple test and making it pass. Once I have one simple test passing, it becomes easy to add more. The key is get started with the simplest test possible. This page explains how I do that.

The most basic PHPUnit test for Drupal

The most basic test looks something like this:

<?php
namespace Drupal\Tests\my_module\Functional;

use Drupal\Tests\BrowserTestBase;

class MyModuleTest extends BrowserTestBase {

  /**
   * Modules to enable.
   *
   * @var array<string>
   */
  protected static $modules = ['my_module'];

  /**
   * Theme to enable. This field is mandatory.
   *
   * @var string
   */
  protected $defaultTheme = 'stark';

  /**
   * The simplest assert possible.
   */
  public function testOne() {
    $this->assertTrue(TRUE);
  }
}

Drupal uses PHPUnit for testing, and the test above is a PHPUnit test.

The test lives in docroot/modules/custom/my_module/tests/src/Functional/MyModuleTest.php.

Installing PHPUnit for Drupal

Drupal does not ship with PHPUnit out-of-the-box, so it needs to be installed.

The best way to install PHPUnit on a Drupal site is by installing the drupal/core-dev package. It can be installed using Composer:

$ composer require drupal/core-dev --dev --update-with-all-dependencies

The command above will download and configure PHPUnit, along with other development dependencies that are considered a best-practice for Drupal development (e.g. PHPStan).

Configuring PHPUnit for Drupal

Once installed, you still have to configure PHPUnit. All you need to do is set two variables:

  • SIMPLETEST_BASE_URL should be the URL of your site (e.g. http://localhost/).
  • SIMPLETEST_DB should be your database settings (e.g. mysql://username:password@localhost/database).
  • BROWSER_OUTPUT_DIRECTORY is optional. If provided, Drupal will store the output of each PHPUnit test in the specified directory. If not provided, no output will be stored.

You can specify these directly in docroot/core/phpunit.xml.dist, or you can set them as environment variables in your shell.

Using PHPUnit with DDEV

I use DDEV for my local development environment and run tests as follows:

$ ddev ssh
$ export SIMPLETEST_BASE_URL="https://dri.es.ddev.site/"
$ export SIMPLETEST_DB="mysql://db:db@db/db"
$ export BROWSER_OUTPUT_DIRECTORY="/var/www/html/phpunit-output"

$ ./vendor/bin/phpunit docroot/modules/custom --verbose -c /var/www/html/docroot/core/phpunit.xml.dist

This sequence of commands logs into the DDEV web server, configures the testing parameters, and then executes all PHPUnit tests in ./docroot/modules/custom.

Using PHPUnit with Lando

If you use Lando for your local development environment, there are a couple of things you can add to your .lando.yml configuration file to make using PHPUnit a bit easier:

services:
  appserver:
    overrides:
      environment:
        SIMPLETEST_BASE_URL: "http://localhost/"
        SIMPLETEST_DB: "mysql://username:password@localhost/database"
        BROWSERTEST_OUTPUT_DIRECTORY: "/app/phpunit-results"
tooling:
  test:
    service: appserver
    cmd: "php /app/vendor/bin/phpunit --verbose -c /app/docroot/core/phpunit.xml.dist"

The first 6 lines sets the variables and the last 4 lines create a new lando test command.

After changing my .lando.yml, I like to rebuild my Lando environment, though that might not be strictly necessary:

$ lando rebuild -y

Now, you can run the PHPUnit test as follows:

$ lando test modules/custom/my_module/tests/src/Functional/MyModuleTest.php