0

I'm trying to get a mock of current user.

$user = \Drupal\user\Entity\User::load(\Drupal::currentUser()->id());

For this, I extend UnitTestCase class and load the User class methods.

$methods = get_class_methods('\Drupal\user\Entity\User');

Since load() is a User class method, I have created a mock of the User class, disabled its constructor, and set all methods of this class, including load() which is the method I actually need.

$user = $this->getMockBuilder('\Drupal\user\Entity\User')
  ->disableOriginalConstructor()
  ->setMethods($methods)
  ->getMock();

Since the method is set now, I'm trying to call this method once and not sure what it will return exactly.

$user->expects($this->once())
  ->method('load')
  ->will($this->returnValue('admin'));

Now, while running this test, I got an error.

Symfony\Component\DependencyInjection\Exception\ServiceNotFoundException: You have requested a non-existent service "entity.manager".

What's the need of injecting the entity.manager service?

Although load() is a method of the entity storage interface, it also exists in the User class.
Why does this error come up?

Can I load the current user without mocking the entity.manager class?

The actual method for which I'm doing unit testing is the following.

public static function get_ctype_field_value($field) {
  $user = user_load(\Drupal::currentUser()->id());
  $ulm = get_type_id($user); 
  $local_market = \Drupal\node\Entity\Node::load($ulm);
  $llf = '';
  if ($local_market) {
    // Get the field value from the LM.
    if ($local_market->hasField($field)) {
      $localmarket_field = $local_market->$field->value;
    }
  }
  return $localmarket_field;
}
0

1 Answer 1

3

In Drupal, unit tests (UnitTestCase or \PHPUnit_Framework_TestCase, sometimes) are really best when you have a class that doesn't have a lot of dependencies or when you can really predict what the dependencies do so you can mock them. Typically, you mock individual methods, and not try to do everything. When you find yourself mocking too much, or with complicated mocks, it is best to rework your test as a kernel test (KernelTestBase or KTB for short).

A KTB will boot a minimal Drupal environment, and then you can enable modules and choose which config and schema you want installed (enabling the module doesn't automatically do this). These are still PhpUnit tests, so you can run that that way and have full access to providers and other PhpUnit features. Many modules in core also define extensions of KTB to provide setup and additional features (eg, EntityKernelTestBase and ViewsKernelTestBase).

KTB tests are not as fast as UTC tests, but still quick and not as slow as functional tests (BrowserTestBase). Core has tons of examples.

In your case, since it seems like you need users and nodes, you really want a KTB. Since both are entities, there is really a lot you would need to mock and you will go down the rabbit hole quickly trying to do this because of the dependencies.

See also Types of tests in Drupal 8.

A few answers to your specific questions.

Users are content entities (so are nodes), which use a lot of services. And, they aren't all properly injected (the base Entity class uses a lot of helper methods that access the global \Drupal class to get services). In addition EntityManager is deprecated and got broken up in different services; so a lot of its methods are really helper functions for the other services. To to a UTC, you would have to start mock these helper functions. I do not think there is a way around this.

Based off your test snippet, you are really best starting off with a KTB.

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.