5

Sometimes I find that I end up having to do lots of mocking just to make the class testable, especially if it is interacting with the Entity API. For example, if I have code like this:

$taxonomy_term_storage = $this->entityTypeManager->getStorage('taxonomy_term');
$category = $taxonomy_term_storage->load($product_category_tid);
$category_atlas_key = $category->get('field_name_key')->getValue();

So now, to mock the return value of one field I need to do all of this:

$fieldItemListMock = $this->getMockBuilder('\Drupal\Core\Field\FieldItemListInterface')
  ->disableOriginalConstructor()
  ->getMock();

$fieldItemListMock->expects($this->any())
  ->method('getValue')
  ->willReturn('foo');

$fieldableEntityMock = $this->getMockBuilder('\Drupal\Core\Entity\FieldableEntityInterface')
  ->disableOriginalConstructor()
  ->getMock()

$fieldableEntityMock->expects($this->any())
  ->method('get')
  ->willReturn($fieldItemListMock);

$entityStorageMock = $this->getMockBuilder('\Drupal\Core\Entity\EntityStorageInterface')
  ->disableOriginalConstructor()
  ->getMock();

$entityStorageMock->expects($this->any())
  ->method('load')
  ->willReturn($fieldableEntityMock);

$this->entityTypeManagerMock->expects($this->any())
  ->method('getStorage')
  ->willReturn($entityStorageMock);

As far as I'm aware I've done everything as I'm supposed to, injecting external dependencies via the constructor but it still seems like way too much effort. The problem gets exponentially worse when I'm working with multiple fields or other people's code who haven't injected dependencies properly. So I end up having to create a partial mock of the class I'm testing.

Browsing through core and contrib modules I notice that there seem to be more Kernel tests than Unit tests, which seems contrary to the testing pyramid

enter image description here

Which makes it seem like they have also found unit tests too hard to set up.

So I'm wondering, is it better to just write Kernel tests / Browser tests for classes that interact with the Entity API or am I simply writing my code wrong, which is making it hard to unit test?

5

So I'm wondering, is it better to just write Kernel tests / Browser tests for classes that interact with the Entity API or am I simply writing my code wrong, which is making it hard to unit test?

In my opinion yes. The Entity API is not designed to work well for mocking/unit tests. Drupal 8 was a very different thing when we started designing and implementing it. Maybe we'd do things differently today, but the kind of extensibility it offers is hard to manage. And we also needed something that we could gradually convert the large Drupal core code base or it would never have been possible.

In regards to the testing pyramid, that is the ideal scenario, but it's not always feasible. I also think that it is makes more sense in a scenario where you built and control the whole system. By building on top of Drupal (which in turn builds on top of Symfony), a huge amount of the complexity and heavily lifting is already taken away from you and covered with the test coverage of those projects. Given that, it makes sense to me that there is a bigger focus on integration/E2E tests as you are mostly integrating existing components.

And if you do have your own components that actually do things worthy of unit tests (and not just shuffle data between forms, entities and templates) then one thing you could do is work with Adapter/Value objects that hide away the complexity of Entity Field API with an interface that you can mock.

| improve this answer | |
  • The adapter object is a good suggestion. I'd never really thought of that. Thanks. – chap Feb 11 '18 at 23:48

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.