Avoiding over-mocking

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).

The Class to be tested (MyClass.php)

<?php

class MyClass {

public function __construct(
private DependencyInterface $dependency
) {
}

public function doSomething() {
$result = $this->dependency->performAction();

return "Result: " . $result;
}
}

Dependency Interface (DependencyInterface.php)

<?php

interface DependencyInterface {

public function performAction();

}

A test class that ends up testing mocks (MyClassTest.php)

<?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);
}

}

Here's the thing

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.