Testing Services
When to Use
Verifying service logic, dependency injection, container integration.
Decision
| Service uses... | Test type | Pattern |
|---|---|---|
| No Drupal dependencies | Unit | Mock all dependencies |
| Database, config, entities | Kernel | Use real container |
| HTTP context, current route | Browser | Full Drupal install |
Pattern
Unit test with mocked dependencies:
namespace Drupal\Tests\my_module\Unit;
use Drupal\my_module\Service\DataProcessor;
use Drupal\Tests\UnitTestCase;
class DataProcessorTest extends UnitTestCase {
public function testProcessData(): void {
$mock_logger = $this->createMock(LoggerInterface::class);
$mock_logger->expects($this->once())->method('info');
$service = new DataProcessor($mock_logger);
$result = $service->processData(['key' => 'value']);
$this->assertEquals('processed', $result['status']);
}
}
Kernel test with real container:
namespace Drupal\Tests\my_module\Kernel;
use Drupal\KernelTests\KernelTestBase;
class MyServiceTest extends KernelTestBase {
protected static $modules = ['system', 'my_module'];
public function testServiceIntegration(): void {
$service = $this->container->get('my_module.my_service');
$result = $service->doSomething();
$this->assertNotEmpty($result);
}
}
Replacing service with mock in Kernel test:
use Drupal\Core\DependencyInjection\ServiceModifierInterface;
class MyServiceTest extends KernelTestBase implements ServiceModifierInterface {
public function alter(ContainerBuilder $container): void {
$container->getDefinition('my_module.external_api')
->setClass(MockExternalApi::class);
}
}
Reference: /core/modules/system/tests/src/Unit/Routing/AdminRouteSubscriberTest.php
Common Mistakes
- Using
\Drupal::service()in service class -- impossible to unit test (inject dependencies via constructor) - Not mocking external API calls -- tests fail when API down, slow tests
- Testing service in isolation when integration matters -- use Kernel test to verify container wiring
- Over-mocking makes test meaningless -- if mocking everything, test verifies nothing
- Forgetting to call
expects()on mock -- mock created but never verified