Partial mocking

Today, I wrote a test whilst fixing a bug in some legacy custom Drupal code.

The code is for a custom block, which can be configured using user-defined settings - including a link URL.

In this case, if the link was null (one hadn't been provided), the link was generated to the home page instead of the desired destination.

My first attempt

There was a combination of settings needed to replicate the bug, such as the current site language, the node type the block was placed on and, of course, an empty link URL.

Because the block uses the current route to get the current node, my first attempt to test this was to use a browser/functional test.

That failed quickly after having to enable various other custom modules due to dependencies and to add and configure unrelated configuration settings.

My second attempt

My second attempt used kernel/integration tests, but as there's no setParameter() method on the route matcher I could use in the test, I'd need to rely on mocking.

In a unit test, everything needs to be mocked, but a kernel test allows me to be more selective, only mock what I need, and use the real services for everything else - a.k.a. partial mocking.

The result

I replicated the bug by setting the default and current languages, creating a mock language manager, creating a node of the required type and returning it from a mocked route match.

Everything else remained the same.

Then, I fixed the bug and used a data provider to provide different variables into the test so each use case was covered.

Here's the thing

The whole test file is 129 lines and would have been much more if I'd had to replicate all the configuration in a functional test or mock everything in a unit test.

An integration test with partial mocking was ideal in this case, as it gave me the most flexibility to test what I needed whilst keeping the code simple.

Whilst I'm aware of over-using mocks, this was an ideal situation to use them.