From 716e14bddb30caaf91df5aa8299685a38d43b5c6 Mon Sep 17 00:00:00 2001 From: Oliver Davies Date: Tue, 28 Nov 2023 00:21:47 +0000 Subject: [PATCH] docs(daily-email): add 2023-11-23 Partial mocking --- src/content/daily-email/2023-11-23.md | 50 +++++++++++++++++++++++++++ 1 file changed, 50 insertions(+) create mode 100644 src/content/daily-email/2023-11-23.md diff --git a/src/content/daily-email/2023-11-23.md b/src/content/daily-email/2023-11-23.md new file mode 100644 index 00000000..f24584ae --- /dev/null +++ b/src/content/daily-email/2023-11-23.md @@ -0,0 +1,50 @@ +--- +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.