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 loading the methods of class User.

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

Now, as load function also exists in this User class, I have created a mock of this User class and disabling its constructor and setting all methods of this class including load method which 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 1 error:

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

Now, my question of interest is what's the need of injecting service entity.manager?? Although load is a method of entity storage interface and also it exists in User class too. Then why this error coming up?

Can I load current user without mocking entity.manager class or entity storage interface?

Actual function for which I'm doing unit testing is:

public static function get_ctype_field_value($field) {

    $user = user_load(\Drupal::currentUser()->id());
    $ulm = get_type_id($user); // another function in some class, return value 445
    $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;
  }
2
  • Can you explain a little bit more about what you are trying to test? Typically, you don't mock the entire class, just a few methods that your class under test will invoke. And, as an aside, if you find yourself mocking too much, you should probably consider a kernel test. – mpdonadio Nov 20 '17 at 19:52
  • I'm trying to do unit testing of a function that fetch any field value of a particular content type. each node belongs to particular user. So, I'm loading current user in order to get nid and from nid I will fetch field value. – Sugandh Khanna Nov 22 '17 at 5:49
1

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, privacy policy and cookie policy

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