A duck working on a laptop
3 July, 2025 //

Mocking in Drupal Tests

#Backend
#Drupal
#Tutorial

Daniel Johnson, Developer at Pivale Drupal agency - A man with dark hair and glasses.
Written by Daniel Johnson Backend developer

Daniel is a backend developer, with a keen focus on end-to-end testing, attention to detail and crafting bespoke ecommerce solutions. Daniel is a graduate of Keele University, with a year's study at VU Amsterdam, achieving a first class degree in Computer Science.

Mocking is an essential technique in unit and functional testing that allows developers to isolate the code being tested by replacing dependencies with controlled substitutes. In Drupal development, where components are highly interconnected, effective mocking is crucial for writing reliable, fast, and maintainable tests.

Why Mock in Drupal Tests?

  1. Isolation: Mocking allows you to test specific functionality without relying on external systems or complex dependencies.
  2. Speed: Tests with mocks run faster than those that need to set up and tear down actual database connections or services.
  3. Control: Mocks give you precise control over the behaviour of dependencies, allowing you to test edge cases and error conditions.
  4. Independence: Your tests become independent of implementation details of other components, making them more resilient to changes elsewhere in the codebase.

Mocking Tools and Frameworks for Drupal

PHPUnit

Drupal 8+ uses PHPUnit as its primary testing framework, which provides built-in mocking capabilities:

  • createMock(): Creates a basic mock object
  • getMockBuilder(): Offers more advanced configuration options
  • getMockForAbstractClass(): Creates mocks for abstract classes
  • getMockForTrait(): Creates mocks for traits
     


Prophecy

Prophecy is a more modern mocking framework that's integrated with PHPUnit and offers a more expressive syntax:

$prophet = new \Prophecy\Prophet();
$service = $prophet->prophesize(MyService::class);
$service->doSomething('input')->willReturn('mocked output');

Drupal Test Classes

Drupal provides several test base classes that help with mocking common Drupal services:

  • UnitTestCase: Base class for unit tests with mocking support
  • KernelTestBase: For tests requiring some Drupal services but not a full bootstrap
  • BrowserTestBase: For functional tests with a full Drupal instance

Common Mocking Techniques in Drupal

1. Mocking Services

Services are a primary target for mocking in Drupal tests. Here's how to mock a service:

// Create a mock service
$service = $this->createMock(MyServiceInterface::class);
$service->method('getData')
  ->willReturn(['mocked' => 'data']);

// Replace the service in the container
$this->container->set('my_service', $service);

2. Mocking the Entity API

Entity mocking is common in Drupal tests:

// Mock a node entity
$node = $this->createMock(NodeInterface::class);
$node->expects($this->once())
  ->method('getTitle')
  ->willReturn('Mocked Title');

3. Mocking the Database Layer

For unit tests, you often need to mock database interactions:

// Mock a database connection
$database = $this->createMock(Connection::class);
$statement = $this->createMock(\PDOStatement::class);
$statement->method('fetchAll')
  ->willReturn([['nid' => 1, 'title' => 'Test']]);
$database->method('query')
  ->willReturn($statement);

4. Mocking HTTP Requests

For external API interactions:

// Mock the HTTP client
$response = $this->createMock(ResponseInterface::class);
$response->method('getBody')
  ->willReturn(json_encode(['status' => 'success']));
$client = $this->createMock(ClientInterface::class);
$client->method('request')
  ->willReturn($response);

Practical Examples

Example 1: Mocking a Custom Service

/**
 * @coversDefaultClass \Drupal\my_module\Service\DataProcessor
 * @group my_module
 */
class DataProcessorTest extends UnitTestCase {

  /**
   * Tests the process method.
   */
  public function testProcess() {
    // Create mocks for dependencies
    $logger = $this->createMock(LoggerInterface::class);
    $config = $this->createMock(ConfigFactoryInterface::class);

    // Configure the config mock
    $configObject = $this->createMock(ImmutableConfig::class);
    $configObject->method('get')
      ->willReturn(['setting' => 'value']);
    $config->method('get')
      ->willReturn($configObject);

    // Create the service with mocked dependencies
    $processor = new DataProcessor($logger, $config);

    // Test the service
    $result = $processor->process(['input' => 'data']);
    $this->assertEquals('expected output', $result);
  }
}

Example 2: Mocking the Entity Type Manager

/**
 * @coversDefaultClass \Drupal\my_module\NodeStatistics
 * @group my_module
 */
class NodeStatisticsTest extends UnitTestCase {

  /**
   * Tests the getPublishedCount method.
   */
  public function testGetPublishedCount() {
    // Create a mock entity type manager
    $entityTypeManager = $this->createMock(EntityTypeManagerInterface::class);

    // Create a mock node storage
    $nodeStorage = $this->createMock(EntityStorageInterface::class);

    // Configure the entity type manager to return our mock storage
    $entityTypeManager->method('getStorage')
      ->with('node')
      ->willReturn($nodeStorage);

    // Configure the node storage to return a count
    $nodeStorage->method('getQuery')
      ->willReturnCallback(function() {
        $query = $this->createMock(QueryInterface::class);
        $query->method('condition')->willReturnSelf();
        $query->method('count')->willReturnSelf();
        $query->method('execute')->willReturn(42);
        return $query;
      });

    // Create the service with mocked dependencies
    $statistics = new NodeStatistics($entityTypeManager);

    // Test the method
    $count = $statistics->getPublishedCount();
    $this->assertEquals(42, $count);
  }
}

Best Practices for Mocking in Drupal

  1. Mock interfaces, not implementations: Whenever possible, mock interfaces rather than concrete classes to ensure your tests aren't tightly coupled to specific implementations.
  2. Only mock what you need: Don't mock everything. Mock only the dependencies that are directly relevant to the test.
  3. Use test doubles appropriately:
    • Stubs for providing canned answers
    • Mocks for verifying interactions
  4. Keep mocks simple: Overly complex mocks can make tests hard to understand and maintain.
  5. Test the contract, not the implementation: Focus on testing the expected behaviour, not the internal implementation details.
  6. Use Drupal's testing infrastructure: Take advantage of Drupal's testing classes and traits that provide pre-configured mocks for common Drupal services.
  7. Consider dependency injection: Design your code with dependency injection in mind to make it more testable and easier to mock dependencies.

Effective mocking is a crucial skill for Drupal developers who want to write robust, maintainable tests. By isolating components and controlling their dependencies, you can create tests that are faster, more reliable, and better at catching regressions.

Drupal's modern architecture, with its emphasis on services and dependency injection, makes it particularly well-suited for mocking techniques. Whether you're writing unit tests, kernel tests, or functional tests, understanding how to properly mock Drupal's components will help you build a more reliable test suite and, ultimately, a more stable application.

Remember that while mocking is powerful, it's just one tool in your testing toolkit. Combine it with other testing approaches like integration tests and end-to-end tests to ensure comprehensive coverage of your Drupal application.

Additional Resources:

Daniel Johnson, Developer at Pivale Drupal agency - A man with dark hair and glasses.
Written by Daniel Johnson Backend developer

Daniel is a backend developer, with a keen focus on end-to-end testing, attention to detail and crafting bespoke ecommerce solutions. Daniel is a graduate of Keele University, with a year's study at VU Amsterdam, achieving a first class degree in Computer Science.

Pri Scarabelli, Frontend Developer at Pivale digital transformation agency - a woman with dark hair, glasses, and a big smile

Contact us



Or send us a message...