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: |
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.
Here's an example (thanks, ChatGPT, for the code).
<?php
class MyClass {
public function __construct(
private DependencyInterface $dependency
) {
}
public function doSomething() {
$result = $this->dependency->performAction();
return "Result: " . $result;
}
}
<?php
interface DependencyInterface {
public function performAction();
}
<?php
use PHPUnit\Framework\TestCase;
class MyClassTest extends TestCase {
public function testDoSomething() {
// Creating a mock of the DependencyInterface.
$dependencyMock = $this->createMock(DependencyInterface::class);
// Setting up the mock to return a specific value.
$dependencyMock->expects($this->once())
->method('performAction')
->willReturn('Mocked result');
// Creating an instance of MyClass with the mock.
$myClass = new MyClass($dependencyMock);
// Calling the method to be tested.
$result = $myClass->doSomething();
// Asserting that the result matches the expected value.
$this->assertEquals('Result: Mocked result', $result);
}
}
In this example, the test creates a mock for the DependencyInterface
and sets up an expectation that the performAction method will be called once, returning a specific value.
The test then calls the doSomething
method on MyClass
and asserts that the result is as expected.
The issue with this test is that it's not testing the actual behaviour of MyClass
.
It's only testing that the mock is configured correctly.
If the real implementation of MyClass
has a bug, this test won't catch it.
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.
Here's an example (thanks, ChatGPT, for the code).
<?php
class MyClass {
public function __construct(
private DependencyInterface $dependency
) {
}
public function doSomething() {
$result = $this->dependency->performAction();
return "Result: " . $result;
}
}
<?php
interface DependencyInterface {
public function performAction();
}
<?php
use PHPUnit\Framework\TestCase;
class MyClassTest extends TestCase {
public function testDoSomething() {
// Creating a mock of the DependencyInterface.
$dependencyMock = $this->createMock(DependencyInterface::class);
// Setting up the mock to return a specific value.
$dependencyMock->expects($this->once())
->method('performAction')
->willReturn('Mocked result');
// Creating an instance of MyClass with the mock.
$myClass = new MyClass($dependencyMock);
// Calling the method to be tested.
$result = $myClass->doSomething();
// Asserting that the result matches the expected value.
$this->assertEquals('Result: Mocked result', $result);
}
}
In this example, the test creates a mock for the DependencyInterface
and sets up an expectation that the performAction method will be called once, returning a specific value.
The test then calls the doSomething
method on MyClass
and asserts that the result is as expected.
The issue with this test is that it's not testing the actual behaviour of MyClass
.
It's only testing that the mock is configured correctly.
If the real implementation of MyClass
has a bug, this test won't catch it.