1

I have the a service definition in a custom Drupal 8 module which I would like to test. I've managed to test everything else in my module with unit tests, so my whole suite runs in a fraction of a second, and I'd like to avoid introducing anything Simpletest-based. (My CI infrastructure wouldn't support it anyway.) Is there any way to test my service definition in an isolated unit test? Here's my service definition:

my_module.services.yml

services:
  my_module.client:
    class: Drupal\my_module\Client
    factory: Drupal\my_module\Client::create
    arguments: ['@state', '@config.factory']```

The manual test I've been performing is to run this Drush command.

drush ev 'var_dump(\Drupal::service("my_module.client")->_serviceId == "my_module.client" ? "PASS" : "FAIL");'

That's a sufficient smoke test while I'm developing. For a regression test, I'd also like to assert that the class returned is an instance of the correct type.

2
  • Are you trying to test the service definition in the YAML file? Or are you trying to test the container code? I think these are covered by core's unit tests because it's not your module's code that is doing the instantiating. For instance ContainerTest tests setting a service in the container and YamlFileLoader comes from Syfmony and tested there. I would test the class methods itself, but it's possible to set the object into the container for a given service id and assert that it's returned via \Drupal::service().
    – mradcliffe
    Dec 4, 2015 at 12:55
  • I think what I'm really after is proving that my service definition YAML causes the correct dependencies to be injected into my service class. Maybe that's an integration test by definition. Dec 5, 2015 at 3:20

1 Answer 1

0

Great question, i was wondering this myself, too.

But first: Does this make sense at all? Yes, a pure API module that does not have an integration with it, should test its API.

And: Is it worth it? The performance is in my case:

  • Unit test: ~40ms
  • Kernel test: ~400ms

But note that the unit test may be much more complex, and miss some failures that the kernel test covers (like a broken .info.yml, or the work of service providers).

That said, here's the shootout for my sessionless module:

UnitTest:

<?php

declare(strict_types=1);
namespace Drupal\Tests\sessionless\Unit;

use Drupal\Core\DependencyInjection\ContainerBuilder;
use Drupal\Core\DependencyInjection\YamlFileLoader;
use Drupal\Core\KeyValueStore\KeyValueMemoryFactory;
use Drupal\Core\State\State;
use Drupal\sessionless\TokenGeneration\TokenServiceInterface;
use Drupal\Tests\UnitTestCase;
use Symfony\Component\DependencyInjection\ParameterBag\ParameterBag;

final class ServicesUnitTest extends UnitTestCase {

  protected $container;

  protected function setUp(): void {
    parent::setUp();

    $moduleRoot = dirname(dirname(dirname(__DIR__)));
    // @see \Drupal\Core\DrupalKernel::compileContainer
    $container = new ContainerBuilder(new ParameterBag());
    // Add all external dependencies, maybe as doubles or mocks.
    $container->set('state', new State(new KeyValueMemoryFactory()));
    // Load the services.yml file
    $yamlLoader = new YamlFileLoader($container);
    $yamlLoader->load("$moduleRoot/sessionless.services.yml");
    $container->compile();
    $this->container = $container;
  }

  public function testServices(): void {

    $this->assertInstanceOf(TokenServiceInterface::class, $this->container->get('sessionless.encrypted_signed_token_service'));

    $this->assertInstanceOf(TokenServiceInterface::class, $this->container->get('sessionless.only_signed_token_service'));

  }

}


KernelTest:

<?php

declare(strict_types=1);
namespace Drupal\Tests\sessionless\Kernel;

use Drupal\KernelTests\KernelTestBase;
use Drupal\sessionless\TokenGeneration\TokenServiceInterface;

final class ServicesKernelTest extends KernelTestBase {

  protected static $modules = ['sessionless'];

  public function testServices(): void {
    $this->assertInstanceOf(TokenServiceInterface::class, $this->container->get('sessionless.encrypted_signed_token_service'));
    $this->assertInstanceOf(TokenServiceInterface::class, $this->container->get('sessionless.only_signed_token_service'));
  }

}


2
  • Thanks, @geek-merlin. I used to insist on having unit tests for everything, but I've since concluded that they don't make sense all the time. This is a perfect case of something that's integrated by its nature. Great answer. Dec 27, 2023 at 18:15
  • @TravisCarden Well, in fact i was thinking along the same lines, which is why i found your question! Dec 28, 2023 at 14:20

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.