Sobes.tech
Middle

What is the difference between stop and mock?

sobes.tech AI

Answer from AI

stop is a technique for isolating a test from direct dependencies (such as calls to third-party APIs, databases) by replacing real objects with test doubles. It is used to control the behavior of external dependencies and ensure test reproducibility.

mock (short for "mock object") is a type of test double that not only replaces a real object but also allows verifying how the tested code interacts with it. Mocks can be used to assert calls to methods, their arguments, and the number of calls.

Thus, stop is a more general concept describing isolation, while mock is a specific tool to achieve it, adding the ability to verify interactions.

An example using PHPUnit and Mockery:

<?php

use PHPUnit\Framework\TestCase;
use Mockery;

// Class using an external dependency
class UserProcessor
{
    private $apiClient;

    public function __construct(ApiClient $apiClient)
    {
        $this->apiClient = $apiClient;
    }

    public function processUserData(int $userId): bool
    {
        $data = $this->apiClient->fetchUserData($userId);

        if ($data && $data['status'] === 'active') {
            // Logic for processing an active user
            return true;
        }
        return false;
    }
}

// Example of using a mock for testing
class UserProcessorTest extends TestCase
{
    public function testProcessUserDataWithActiveUser()
    {
        // Create a mock for ApiClient
        $apiClientMock = Mockery::mock(ApiClient::class);

        // Set expected behavior for the mock
        // Expect fetchUserData to be called with argument 123
        $apiClientMock->shouldReceive('fetchUserData')
                      ->with(123)
                      ->andReturn(['status' => 'active', 'data' => '...']) // Mock returns this data
                      ->once(); // Expect the method to be called exactly once

        // Create the object under test, passing the mock
        $userProcessor = new UserProcessor($apiClientMock);

        // Call the method under test
        $result = $userProcessor->processUserData(123);

        // Assert the result
        $this->assertTrue($result);

        // Verify that all mock expectations were met
        Mockery::close();
    }
}

In this example, ApiClient is replaced with a "mock". We "stub" the real API call and simultaneously set up the mock to return specific data when fetchUserData(123) is called. We also verify that this method was called with the correct arguments and exactly once. This is the key difference: a mock allows interaction verification.