---
title: >
    Avoiding over-mocking
pubDate: 2023-11-16
permalink: >-
    archive/2023/11/16/avoiding-over-mocking
tags:
    - software-development
    - automated-testing
    - test-driven-development
---

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)

```language-php
<?php

class MyClass {

  public function __construct(
    private DependencyInterface $dependency
  ) {
  }

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

    return "Result: " . $result;
  }
}
```

## Dependency Interface (DependencyInterface.php)

```language-php
<?php

interface DependencyInterface {

  public function performAction();

}
```

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

```language-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.