Drupal 8/9: Unit Test cases mocking the global Drupal object and Services

Vishwa Chikate
2 min readMar 18, 2022

--

In this article we will discuss on how to mock the global Drupal object when writing unit test cases for the custom code. Let us start by checking the code against which we need to write our Test case/s.

The Code Snippet

Below is a normal Service/Utility class having set of helpful methods. Showing only a single method for example purpose.

We can conclude the following observations ::

  1. The class needs an instance of “\Drupal\Core\Config\ConfigFactoryInterfaceprovided via constructor injection.
  2. Test case to be written to check the return type/value of the method “getLogoutLink()” .
  3. The method “getLogoutLink” depends on the global \Drupal object to return the final value.

Above were my initial understanding, and after writing the test case/s i got the below error 😕

1) Drupal\Tests\authzero\Unit\AuthZeroServiceTest::testGetLogoutLinkDrupal\Core\DependencyInjection\ContainerNotInitializedException: \Drupal::$container is not initialized yet. \Drupal::setContainer() must be called with a real container.

The requested service “\Drupal::request()” has not been initialised yet and is unavailable. Calling “\Drupal::request()” returns an instance of “Symfony\Component\HttpFoundation\RequestStack” equivalent to loading the request_stack service (\Drupal::service(‘request_stack’)).

The Solution

To write proper executable test case the following things were necessary to implement :

  1. Mock the ConfigFactoryInterface instance and will be passed as a constructor parameter to AuthZeroService class. Add the corresponding methods and params that will be invoked in actual code.
  2. Mock the ImmutableConfig class, this is returned by the object of type ConfigFactoryInterfaceon passing the name of the config. Add the corresponding methods and params that will be invoked in actual code.
  3. Mock the RequestStack class which allows to implement the method “getCurrentRequest()” and returns the Request object (#4).
  4. Mock the Request class which allows to implement the method “getSchemeAndHttpHost()”.
  5. Creating a new Container to associate the “request_stack” service with the RequestStack mock object.

Note :: We will use Prophecy object mocking approach in the example test case rather than the PhpUnit approach. For more details check the following article https://www.drupal.org/docs/testing/phpunit-in-drupal/comparison-with-phpunit-mocks.

Test case result 😀

Testing /app/modules/custom/authzero
......
6 / 6 (100%)
Time: 00:00.237, Memory: 14.00 MB
OK (6 tests, 8 assertions)

Final Notes

The DrupalPractise coding standard states not to use global Drupal objects directly in the code, but rather to Inject them. In many cases it would be difficult to avoid them as we want, not to inject many objects in a single class as it is better to directly use them.

Prophecy object mocking approach is better and easier than the PHPUnit way of mocking 😄

--

--