1

I am trying to mock the render() function from common.inc in a test.

I am aware that render() could be substituted with a renderer service, but in this specific case I can't/couldn't refactor the code itself. Nor can I use an external lib for it.

Is there a way to do this in a native way, using PHPUnit only?

2
  • Got it, my problem could be solved by injecting fixtures into the setUp method of the test! drupal.org/docs/8/phpunit/…
    – spiridon
    Commented Dec 17, 2019 at 13:06
  • 2
    If you have found the answer, please post it as an answer here and accept it, to help others. Commented Dec 17, 2019 at 13:10

2 Answers 2

2

Yes, this is possible and done in a handful of places in core. One example is TimeTest. I am not 100% sure it is official, but I call it a shadow function.

The trick is to declare the procedural function in the same namespace as the caller. As an example the Drupal\Component\Datetime\Time class has a method

public function getCurrentTime() {
  return time();
}

this calls out the PHP internal function time(). TimeTest sets up

namespace Drupal\Component\Datetime;

/**
 * Shadow time() system call.
 *
 * @returns int
 */
function time() {
  return 12345678;
}

When PHP chases the scope for resolving a reference, it will check the current namespace first. By declaring the namespace, the procedural function declaration ends up that namespace instead of the global one (\). And since the test class only gets loaded during tests, you don't end up polluting the namespace with a bad function.

2

I have found a solution on this page: https://www.drupal.org/docs/8/phpunit/unit-testing-more-complicated-drupal-classes

You can mock a global function by adding fixtures in your test module. Let's say that you need to mock base_path().

  1. Simple go add a fixture in your testing src

  2. Add a mock for function, for example, you can define like above:

  3. Simply use require_once on your setup and you get your mocked function available and replaceable only in the test you are requiring. Make sure to use function_exists() to check if the function you need to test isn't already available.

 /**
  * Overrides global function if not exists.
  *
  * @return string
  *   Base path mocked.
  */
  function base_path() {
    if (!function_exists('base_path')) {
      return '/';
    }
  }

In my case, I have used fixtures, as refactoring the code was out of question.

As the documentation says, I've created a mocked function in tests/fixtures/function_name.php and included the file into the setUp() method of the test with require_once. This way, I've had my own global function in the test's scope.

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.