0

I'm building a custom module (for use on multiple projects) with code that relies on stuff from Drupal core and third party modules (e.g. extending classes, implementing interfaces, annotating as plugins, etc.). I would like to start writing tests for them, with unit tests to begin with. But so far, all of the resources point to putting the module in a Drupal installation and test in that setup, as if I'm running a full Drupal site - even for a unit test.

I was more imagining that my module would have the runner, the dependencies, and Drupal core be dependencies (or dev dependencies) - just like how JavaScript tests are usually written, whether it's unit tests or headless browser tests. That is, JavaScript testing doesn't require you to pop your code in some other code before you can start testing.

Can this be achieved? Or is putting the my modules code in a Drupal install really the only way to test Drupal modules?

4
  • 2
    Unit tests do not bootstrap the whole system, and run very fast. Kernel tests, functional tests, and JavaScript tests require bootstrapping the system, and take longer.
    – Jaypan
    Mar 16, 2022 at 0:57
  • @Jaypan Yup, I'm aware of the kinds of tests and how they run. The question is more like "can Drupal core and third-party modules be 'dev dependencies' so I can satisfy my modules dependencies during testing and run my unit tests without setting up Drupal in a site-like fashion?"
    – Joseph
    Mar 16, 2022 at 1:10
  • 1
    Not exactly, as you would then be testing the external code, rather than your own unit of code. In this case you instead create mocks/stubs, which imitate the service you are trying to call: drupal.org/docs/automated-testing/phpunit-in-drupal/…
    – Jaypan
    Mar 16, 2022 at 1:16
  • I put those last two comments together into a more comprehensive reply to the original question.
    – Jaypan
    Mar 16, 2022 at 15:21

1 Answer 1

2

Unit tests do not bootstrap the whole system, and run very fast. Kernel tests, functional tests, and JavaScript tests require bootstrapping the system, and take longer.

With unit testing, you don't declare dependencies upon foreign code. This is because tests unit test a piece of code, not the foreign code. If an error was introduced into the foreign code, and the code being tested depended upon that code, the tests would fail, even though the code being tested was still correct. This would be a false fail, and a developer would probably spend time trying to figure out why their code had failed, even though it had not.

The solution is to use mocks to stub the data. A mock is a fake service, created within the test, that simulates the actual dependent service. So when the code being tested makes a call to foreign code, the mock returns a response (aka a stub) as if the foreign code had responded, taking away any risk of false positives from the foreign code failing, since your test will always respond, and will always respond exactly as you set it to.

2
  • I get that I can mock dependencies (e.g. services, arguments, etc.). I was more wondering what happens to classes declared in use, or the class I'm extending, or the interface I'm implementing, or the traits I'm applying. For example, I build a plugin extending core's PluginBase. Do I need to do anything special for my test with regards to PluginBase? Does the test go looking for PluginBase? Do I need the real PluginBase? Or do I have to use a fake PluginBase? I'm just testing some basic logic in that plugin, not the whole plugin mechanism.
    – Joseph
    Mar 16, 2022 at 17:03
  • 1
    I would suggest looking at some examples in core, or opening new tickets for your questions, as I feel the original question has been answered, that being that you use mocks to deal with dependencies in unit tests. And as core modules are doing this, yes, use declarations will work fine.
    – Jaypan
    Mar 16, 2022 at 21:44

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.