oliverdavies.uk/content/node.1fd87ecf-4269-4874-859e-d49c238694bf.yml

197 lines
6.2 KiB
YAML

uuid:
- value: 1fd87ecf-4269-4874-859e-d49c238694bf
langcode:
- value: en
type:
- target_id: daily_email
target_type: node_type
target_uuid: 8bde1f2f-eef9-4f2d-ae9c-96921f8193d7
revision_timestamp:
- value: '2025-05-11T09:00:28+00:00'
revision_uid:
- target_type: user
target_uuid: b8966985-d4b2-42a7-a319-2e94ccfbb849
revision_log: { }
status:
- value: true
uid:
- target_type: user
target_uuid: b8966985-d4b2-42a7-a319-2e94ccfbb849
title:
- value: |
Avoiding over-mocking
created:
- value: '2023-11-16T00:00:00+00:00'
changed:
- value: '2025-05-11T09:00:28+00:00'
promote:
- value: false
sticky:
- value: false
default_langcode:
- value: true
revision_translation_affected:
- value: true
path:
- alias: /daily/2023/11/16/avoiding-over-mocking
langcode: en
body:
- value: |
<p>In unit tests, and sometimes in kernel tests, you need to mock the dependencies you aren't testing, but you can over-mock and only be testing the mocks and not the code you want to test.</p>
<p>Here's an example (thanks, ChatGPT, for the code).</p>
<h2 id="the-class-to-be-tested-myclass.php">The Class to be tested (MyClass.php)</h2>
<pre><code class="language-php">&lt;?php
class MyClass {
public function __construct(
private DependencyInterface $dependency
) {
}
public function doSomething() {
$result = $this-&gt;dependency-&gt;performAction();
return "Result: " . $result;
}
}
</code></pre>
<h2 id="dependency-interface-dependencyinterface.php">Dependency Interface (DependencyInterface.php)</h2>
<pre><code class="language-php">&lt;?php
interface DependencyInterface {
public function performAction();
}
</code></pre>
<h2 id="a-test-class-that-ends-up-testing-mocks-myclasstest.php">A test class that ends up testing mocks (MyClassTest.php)</h2>
<pre><code class="language-php">&lt;?php
use PHPUnit\Framework\TestCase;
class MyClassTest extends TestCase {
public function testDoSomething() {
// Creating a mock of the DependencyInterface.
$dependencyMock = $this-&gt;createMock(DependencyInterface::class);
// Setting up the mock to return a specific value.
$dependencyMock-&gt;expects($this-&gt;once())
-&gt;method('performAction')
-&gt;willReturn('Mocked result');
// Creating an instance of MyClass with the mock.
$myClass = new MyClass($dependencyMock);
// Calling the method to be tested.
$result = $myClass-&gt;doSomething();
// Asserting that the result matches the expected value.
$this-&gt;assertEquals('Result: Mocked result', $result);
}
}
</code></pre>
<h2 id="here%27s-the-thing">Here's the thing</h2>
<p>In this example, the test creates a mock for the <code>DependencyInterface</code> and sets up an expectation that the performAction method will be called once, returning a specific value.</p>
<p>The test then calls the <code>doSomething</code> method on <code>MyClass</code> and asserts that the result is as expected.</p>
<p>The issue with this test is that it's not testing the actual behaviour of <code>MyClass</code>.</p>
<p>It's only testing that the mock is configured correctly.</p>
<p>If the real implementation of <code>MyClass</code> has a bug, this test won't catch it.</p>
format: full_html
processed: |
<p>In unit tests, and sometimes in kernel tests, you need to mock the dependencies you aren't testing, but you can over-mock and only be testing the mocks and not the code you want to test.</p>
<p>Here's an example (thanks, ChatGPT, for the code).</p>
<h2 id="the-class-to-be-tested-myclass.php">The Class to be tested (MyClass.php)</h2>
<pre><code class="language-php">&lt;?php
class MyClass {
public function __construct(
private DependencyInterface $dependency
) {
}
public function doSomething() {
$result = $this-&gt;dependency-&gt;performAction();
return "Result: " . $result;
}
}
</code></pre>
<h2 id="dependency-interface-dependencyinterface.php">Dependency Interface (DependencyInterface.php)</h2>
<pre><code class="language-php">&lt;?php
interface DependencyInterface {
public function performAction();
}
</code></pre>
<h2 id="a-test-class-that-ends-up-testing-mocks-myclasstest.php">A test class that ends up testing mocks (MyClassTest.php)</h2>
<pre><code class="language-php">&lt;?php
use PHPUnit\Framework\TestCase;
class MyClassTest extends TestCase {
public function testDoSomething() {
// Creating a mock of the DependencyInterface.
$dependencyMock = $this-&gt;createMock(DependencyInterface::class);
// Setting up the mock to return a specific value.
$dependencyMock-&gt;expects($this-&gt;once())
-&gt;method('performAction')
-&gt;willReturn('Mocked result');
// Creating an instance of MyClass with the mock.
$myClass = new MyClass($dependencyMock);
// Calling the method to be tested.
$result = $myClass-&gt;doSomething();
// Asserting that the result matches the expected value.
$this-&gt;assertEquals('Result: Mocked result', $result);
}
}
</code></pre>
<h2 id="here%27s-the-thing">Here's the thing</h2>
<p>In this example, the test creates a mock for the <code>DependencyInterface</code> and sets up an expectation that the performAction method will be called once, returning a specific value.</p>
<p>The test then calls the <code>doSomething</code> method on <code>MyClass</code> and asserts that the result is as expected.</p>
<p>The issue with this test is that it's not testing the actual behaviour of <code>MyClass</code>.</p>
<p>It's only testing that the mock is configured correctly.</p>
<p>If the real implementation of <code>MyClass</code> has a bug, this test won't catch it.</p>
summary: null
field_daily_email_cta: { }