Writing Automated Update Tests for Drupal 8 (or later)

Last updated on
13 November 2025

If your module is making a data model change related to configuration, then you need to properly update your data model (as described on child pages linked to from that page).

You'll also need to test your update, to verify that it is working correctly. You can test it manually, but it is also a good idea (and required in Core development) to write an automated upgrade test for your change. This page describes how to do that.

Outline of the steps

The basic idea of an automated test for an update is:

  1. Make a test class that extends \Drupal\FunctionalTests\Update\UpdatePathTestBase.
  2. Set up the database and configuration to match the "prior" data model. There is a standard database dump file to use to get the basics, and then you'll write a PHP file that makes additions to set up your data (examples below). The test will execute both the standard database dump file and your custom PHP file, to set up the database and configuration.
  3. Run the update using the method in the test class (shown below).
  4. Verify that the resulting database/configuration matches the "new" data model

Details of the process are in the following sections. Specific testing examples can be found by searching for classes that extend UpdatePathTestBase.

Making a setup file

Automated update tests make use of one or more "setup" files, which are PHP files that, when executed, will set up the database and configuration the way it should be prior to updates being run.

There are files that you can use as a base in core/modules/system/tests/fixtures/update. There are usually two dumps of the standard install, one with data and one without data. The one with data has filled in the name and other one has bare.

You'll need to write an additional file that sets up your database tables or configuration matching your prior data model. Examples:

  • If your data model change involves making changes to database schema, you'd want to set up your database tables and probably put some data in them.
  • If your data model change involves configuration, you'd want to import configuration that has examples of the old configuration that you want to update and verify.

A good way to import configuration is like this, assuming that you've exported your configuration to a file in the same directory as this PHP file:

use Drupal\Core\Database\Database;

$connection = Database::getConnection();

// Import YML config files.
$configs = [];
$configs[] = \Drupal\Component\Serialization\Yaml::decode(file_get_contents(__DIR__ . '/EXPORTED_CONFIG_FILENAME.yml'));

// Save them in the database.
foreach ($configs as $config) {
$connection->insert('config')
  ->fields([
      'collection',
      'name',
      'data',
    ])
  ->values([
      'collection' => '',
      'name' => 'YOUR_CONFIG_TYPE_PREFIX.' . $config['id'],
      'data' => serialize($config),
    ])
  ->execute();
}

Making a setup file to include a core module not enabled in the Standard profile

If you need to write an update path test for a core module that's not enabled in the Standard profile, things can get a little complicated. In some cases, you might need to create your own database dump from scratch. However, it's possible (with some manual effort) to craft a setup file that can be applied on top of one of the full "standard-base" fixtures provided by core (located in core/modules/system/tests/fixtures/update). The process is:

  1. Create a clean database to work from.
  2. Checkout or otherwise install an unmodified Drupal core 9.0.0 codebase.
  3. Perform a clean install of 9.0.0 with the 'standard' profile (e.g. drush si standard if you're using drush).
  4. Run core/scripts/dump-database-d8-mysql.php to generate a "bare" 9.0.0 dump. Core provides one, but to make the next steps easier, you'll want to do this yourself.
  5. Install the non-standard core modules you need (e.g. content_moderation + workflows).
  6. Run dump-database-d8-mysql.php again to get the new database state with the new modules enabled.
  7. Diff the two DB dumps to see the differences.
  8. Copy the relevant bits into your module-specific setup file (e.g. content_moderation.php)

An example of this approach is available at #3150294-53: New translations for moderated nodes are not created in the initial workflow state if you want to see it in action.

Writing the test

Once you have created the PHP file that creates your "prior" data, you'll need to write a test that runs the update and verifies the resulting data. Here's a skeleton:

namespace Drupal\YOURMODULE\Tests\Functional\Update;

use Drupal\FunctionalTests\Update\UpdatePathTestBase;

/**
 * Provides tests for the DESCRIBE UPDATE HERE.
 */
class YourClassNameEndsInTest extends UpdatePathTestBase {

  /**
   * {@inheritdoc}
   */
  protected function setDatabaseDumpFiles() {
    // Note that contributed modules must use an absolute path of
    // DRUPAL_ROOT . '/core/modules/system/tests/fixtures/update/drupal-8.bare.standard.php.gz'
    // to drupal-8.bare.standard.php.gz, because the relative path to core in
    // the testbot is not guaranteed to be the same as what you use on your site.
    // If however you are writing a core test residing in (for example)
    // /core/modules/foo/src/Tests/Update, a relative path of
    // __DIR__ . '/../../../../system/tests/fixtures/update/drupal-8.bare.standard.php.gz'
    // is preferred.
    $this->databaseDumpFiles = [
      DRUPAL_ROOT . '/core/modules/system/tests/fixtures/update/drupal-8.bare.standard.php.gz',
      __DIR__ . 'PATH TO YOUR PHP SETUP FILE',
    ];
  }

  /**
   * Tests that DESCRIBE YOUR UPDATE HERE.
   */
  public function testUpdateHookN() {
    // Run the updates.
    $this->runUpdates();

   // Now load your data and test it.
  }
}

Creating your own dump

There are situations where the existing dump files in core are not suitable and a new dump file is needed.

The database dump should match the prior data model and thus it must be built using the system requirements for the version of Drupal core that the prior model applies to.  And, if applicable, the version of any contributed or custom modules that the prior module applies to.

  1. Determine the requirements for the prior data model
    1. The version of Drupal core.
    2. The PHP version.
    3. If this is for a contributed or custom module, then the version of the module.
  2. Build the database dump
    1. Create an clean working environment.
    2. Use git to checkout the version of Drupal, contributed and custom modules (if required) that applies to the prior data model. This must not include any of the update hooks that will be tested..
    3. Install Drupal core at the version decided above, standard install.
    4. Enable all of the database driver modules so that your update test works regardless of database engine. i.e. mysql, pgsql and sqlite modules.
  3. Create the dump, using the script from the next major version.
    1. Use git to checkout the next major version of Drupal.
    2. php ./core/scripts/db-tools.php dump-database-d8-mysql | gzip > YOUR_MODULE_PATH/tests/fixtures/update/YOUR_DUMP_NAME.php.gz

The database dump, YOUR_DUMP_NAME.php.gz, now contains the prior database and is ready for use in a test of the update hook(s).

Help improve this page

Page status: No known problems

You can: