51 lines
2.1 KiB
Markdown
51 lines
2.1 KiB
Markdown
---
|
|
title: >
|
|
Partial mocking
|
|
pubDate: 2023-11-23
|
|
permalink: >-
|
|
archive/2023/11/23/partial-mocking
|
|
tags:
|
|
- automated-testing
|
|
- test-driven-development
|
|
- drupal
|
|
- php
|
|
- phpunit
|
|
- phpc
|
|
---
|
|
|
|
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.
|