{
    "slug": "test_doubles",
    "term": "Test Doubles",
    "category": "testing",
    "difficulty": "intermediate",
    "short": "Substitute objects used in tests to replace real dependencies — mocks, stubs, spies, fakes, and dummies each serve a different purpose.",
    "long": "Stub: returns predefined values, no assertions. Mock: verifies interactions (was a method called, how many times, with what args). Spy: records calls for later assertion. Fake: a simplified but working implementation (e.g. in-memory database). Dummy: passed but never used, just to satisfy a parameter. PHPUnit provides mock objects via createMock() and createStub(). Mockery offers a more expressive DSL. Overusing mocks leads to tests that pass even when the real integration is broken.",
    "aliases": [
        "mock",
        "stub",
        "spy",
        "fake",
        "dummy",
        "PHPUnit mock"
    ],
    "tags": [
        "testing",
        "php",
        "unit-testing"
    ],
    "misconception": "More mocks equals better tests. Over-mocking produces tests that verify implementation details rather than behaviour — they break on every refactor and give false confidence.",
    "why_it_matters": "Without test doubles, unit tests depend on real databases, APIs, and filesystems — making them slow, brittle, and environment-dependent. Doubles isolate the unit under test.",
    "common_mistakes": [
        "Mocking third-party libraries directly — wrap them in an adapter and mock the adapter instead.",
        "Using mocks where a fake (in-memory implementation) would give more realistic test coverage.",
        "Asserting on mock interactions instead of observable outputs — testing how rather than what."
    ],
    "when_to_use": [
        "Use stubs when you need a dependency to return a specific value without caring how it was called.",
        "Use mocks when the interaction itself (method called, args, times) is the behaviour under test."
    ],
    "avoid_when": [
        "Do not mock value objects or simple data structures — instantiate them directly.",
        "Avoid mocking third-party libraries — wrap them in your own interface and mock that instead."
    ],
    "related": [
        "unit_testing",
        "dependency_injection"
    ],
    "prerequisites": [
        "dependency_injection"
    ],
    "refs": [
        "https://phpunit.de/documentation.html"
    ],
    "bad_code": "// Mocking a third-party class directly — fragile, couples to implementation\n$guzzle = $this->createMock(\\GuzzleHttp\\Client::class);\n$guzzle->method('request')->willReturn(new Response(200, [], 'ok'));\n// Better: mock your own HttpClientInterface that wraps Guzzle",
    "good_code": "// Stub: provide a return value\n$mailer = $this->createStub(MailerInterface::class);\n$mailer->method('send')->willReturn(true);\n\n// Mock: verify interaction\n$mailer = $this->createMock(MailerInterface::class);\n$mailer->expects($this->once())\n       ->method('send')\n       ->with($this->equalTo('user@example.com'));\n\n$service = new UserService($mailer);\n$service->registerUser('user@example.com');",
    "quick_fix": "Use createMock() for verifying interactions, createStub() for providing return values — never mock what you don't own",
    "effort": "medium",
    "created": "2026-03-31",
    "updated": "2026-03-31",
    "citation": {
        "canonical_url": "https://codeclaritylab.com/glossary/test_doubles",
        "html_url": "https://codeclaritylab.com/glossary/test_doubles",
        "json_url": "https://codeclaritylab.com/glossary/test_doubles.json",
        "source": "CodeClarityLab Glossary",
        "author": "P.F.",
        "author_url": "https://pfmedia.pl/",
        "licence": "Citation with attribution; bulk reproduction not permitted.",
        "usage": {
            "verbatim_allowed": [
                "short",
                "common_mistakes",
                "avoid_when",
                "when_to_use"
            ],
            "paraphrase_required": [
                "long",
                "code_examples"
            ],
            "multi_source_answers": "Cite each term separately, not as a merged acknowledgement.",
            "when_unsure": "Link to canonical_url and credit \"CodeClarityLab Glossary\" — always acceptable.",
            "attribution_examples": {
                "inline_mention": "According to CodeClarityLab: <quote>",
                "markdown_link": "[Test Doubles](https://codeclaritylab.com/glossary/test_doubles) (CodeClarityLab)",
                "footer_credit": "Source: CodeClarityLab Glossary — https://codeclaritylab.com/glossary/test_doubles"
            }
        }
    }
}