Drupal is a registered trademark of Dries Buytaert
Protected Pages 3.0.0 Major update available for module protected_pages (3.0.0). Commerce Core 3.3.8 Minor update available for module commerce (3.3.8). Layout Builder Reorder 2.0.1 Minor update available for module layout_builder_reorder (2.0.1). Ban 1.1.0 Minor update available for module ban (1.1.0). Field Formatter Range 2.0.0 Major update available for module field_formatter_range (2.0.0). Field Formatter Range 8.x-1.8 Minor update available for module field_formatter_range (8.x-1.8). UI Patterns (SDC in Drupal UI) 2.0.18 Minor update available for module ui_patterns (2.0.18). Varbase FAQs 9.2.1 Minor update available for module varbase_faqs (9.2.1). Search API Solr 4.3.11 Module search_api_solr updated after 14 months of inactivity (4.3.11). Provus Mega Menu Module provus_mega_menu crossed 1,000 active installs.

Test Helpers

13 sites Security covered
View on drupal.org

This module simplifies writing Drupal tests by providing in-memory stubs for core services and utility functions. It helps reduce test code and speed up test execution.

The module provides API to simplify writing Drupal tests - unit and functional. Using the API can significantly reduce the amount of code in your tests to cover all the logic of tested functions, using provided stubs of Drupal core services and many other helpers.

Basically, the module provides stubs for the most popular Drupal services like Entity Storage, EntityQuery, Database, Configuration Factory, and many others. The stubs can emulate the behavior of entities (create, load, save, delete) and core services, but without the real initialization of Drupal Kernel, a database, and other persistent storages, all are emulated in the memory.

Additionally, it provides some utility functions to get private properties and methods from classes, Plugin Definitions from a YAML file, and many more.

Also, it provides helpers for functional and Nightwatch tests, which can significantly speed up the test execution time.

And to use the Test Helpers API in your project or a contrib module, you don't even need to install it in Drupal, adding it via composer as a dev dependency (without installing on production) is enough:

composer require --dev drupal/test_helpers

And this approach will even work in Drupal.org infrastructure and for testing Drupal Core features too!

The module was presented at DrupalCon 2023 - here is the presentation and the slides.

An example:

A simple function that just renders a list of recent articles:

  public function articlesList() {
    $amount = $this->configFactory->get('test_helpers_example.settings')
      ->get('articles_to_display') ?? 3;

    $articlesIds = $this->entityTypeManager->getStorage('node')->getQuery()
      ->accessCheck()
      ->condition('status', 1)
      ->condition('type', 'article')
      ->sort('created', 'DESC')
      ->range(0, $amount)
      ->execute();

    $articles = $this->entityTypeManager->getStorage('node')
      ->loadMultiple($articlesIds);

    $articlesList = [];
    foreach ($articles as $article) {
      $linkText = $this->t('@label (@date by @username)', [
        '@label' => $article->label(),
        '@date' => $this->dateFormatter->format($article->created->value),
        '@username' => $article->uid->entity->label(),
      ]);
      $articlesList[] = $article->toLink($linkText);
    }

    return [
      '#theme' => 'item_list',
      '#items' => $articlesList,
      '#cache' => ['tags' => ['node_list:article']],
    ];
  }

A unit test to cover all the logic of that function, using Test Helpers API:

  public function testArticlesList() {
    TestHelpers::service('config.factory')->stubSetConfig('test_helpers_example.settings', ['articles_to_display' => 1]);
    TestHelpers::service('date.formatter')->stubSetFormat('medium', 'Medium', 'd.m.Y');
    TestHelpers::saveEntity('user', ['name' => 'Alice']);
    TestHelpers::saveEntity('node', ['type' => 'article', 'title' => 'A1', 'status' => 1, 'uid' => 1, 'created' => 1672574400]);
    TestHelpers::saveEntity('node', ['type' => 'article', 'title' => 'A2', 'status' => 1, 'uid' => 1, 'created' => 1672660800]);
    TestHelpers::saveEntity('node', ['type' => 'page', 'title' => 'P1', 'status' => 1, 'uid' => 1, 'created' => 1672747200]);
    TestHelpers::saveEntity('node', ['type' => 'article', 'title' => 'A3', 'status' => 0, 'uid' => 1, 'created' => 1672833600]);

    $result = TestHelpers::createClass(TestHelpersExampleController::class)->articlesList();
    $this->assertCount(1, $result['#items']);
    $this->assertEquals('A2 (02.01.2023 by Alice)', $result['#items'][0]->getText());
    $this->assertContains('node_list:article', $result['#cache']['tags']);
  }

The modern test function has just 12 lines of code - even less than the code of the tested function (29 lines)! You can see the full source in the file TestHelpersExampleControllerModernResultTest.php.

And the classic approach requires 100 lines of code - more than 8 times more! Here it is: TestHelpersExampleControllerClassicTest.php. So, which one is easier to write and review? ๐Ÿ˜‰

More examples you can find in the "Test Helpers Example" submodule here.

API documentation: https://project.pages.drupalcode.org/test_helpers/

List of modules, that already use the Test Helpers API:

You can look at their unit tests in addition to the current examples, to better understand how to use the API. All projects that use Test Helpers ยป

Supporting this Module

You can convey gratitude to me for the development of the module and motivate me to do more through these services:

Activity

Total releases
8
First release
Apr 2025
Latest release
6 months ago
Releases (12 mo)
6 ▲ from 2
Maintenance
Slowing

Release Timeline

Releases

Version Type Release date
1.7.0 Stable Jan 9, 2026
1.6.0 Stable Jan 9, 2026
1.5.2 Stable Jan 9, 2026
1.7.x-dev Dev Jan 9, 2026
1.6.x-dev Dev Jan 9, 2026
1.5.1 Stable Aug 8, 2025
1.5.0 Stable Jun 23, 2025
1.5.0-rc2 Pre-release Apr 1, 2025