{"slug": "solving-the-hallucination-loop-in-ai-generated-unit-tests", "title": "Solving the hallucination loop in AI generated unit tests", "summary": "A developer using Claude 3.5 Sonnet through Cursor spent four hours stuck in a \"hallucination loop\" generating Jest unit tests for a TypeScript payment gateway, because the model assumed standard jest.mock() behavior while the project used a custom ServiceLocator singleton. The tests failed repeatedly with \"TypeError: Cannot read properties of undefined (reading 'processPayment')\" until the developer supplied the dependency-container.ts file and explicitly mocked the singleton instance via ServiceLocator.getInstance before the beforeEach block. The developer's stated fix is to stop prompting for the solution and instead prompt for the AI's assumption about a variable's state at a given line.", "body_md": "# Solving the hallucination loop in AI generated unit tests\n\nI spent four hours last Thursday fighting a ghost in my test suite. I was using Claude 3.5 Sonnet via [Cursor](/en/tags/cursor/) to generate unit tests for a TypeScript payment gateway module. The AI kept generating tests that looked perfect—beautifully structured, covering edge cases, and using Jest mocks—but they failed every single time I ran them.\n\nThe error was always some variation of:`TypeError: Cannot read properties of undefined (reading 'processPayment')`\n\nThe wild part? The AI looked at the error, apologized, and gave me the exact same code back with a different comment. I was stuck in a \"hallucination loop\" where the AI assumed my mock was being injected correctly when, in reality, the dependency injection in my actual project used a custom singleton pattern that the LLM didn't grasp from the provided context.\n\n## Why the AI kept lying about the mocks\n\nThe problem wasn't the logic; it was the context window. I had attached the service file, but not the `dependency-container.ts` file where the actual instantiation happened. The AI assumed I was using standard Jest `jest.mock()` behavior, but my project required a manual override of the singleton instance.\n\nI tried the \"just fix it\" prompt three times. Waste of time.\n\nThe breakthrough happened when I stopped asking the AI to \"fix the error\" and instead asked it to \"explain how it thinks the `PaymentService` is being instantiated in the test environment.\" It admitted it was guessing based on common patterns.\n\nHere is the comparison of what it gave me versus what actually worked:\n\n| Attempt | AI's Assumption | Actual Reality | Result |\n\n| :--- | :--- | :--- | :--- |\n\n| 1 | `jest.mock('./service')` works automatically | Project uses a custom `ServiceLocator` | `TypeError` |\n\n| 2 | Mock should be passed in constructor | Service is a singleton accessed via `.getInstance()` | `TypeError` |\n\n| 3 | (After I provided the container file) Manual override of singleton | Manual override of singleton | **Pass** |\n\n## The fix that actually stopped the loop\n\nInstead of letting the AI guess, I had to be explicit about the mocking strategy. I stopped using the generic \"generate tests\" prompt and switched to a specific implementation pattern.\n\nThe solution was to explicitly mock the singleton instance before the `beforeEach` block.\n\n``` js\n// This is what actually worked after 4 hours of failure\nimport { ServiceLocator } from '../container';\nimport { PaymentService } from './payment.service';\n\njest.mock('../container');\n\ndescribe('PaymentGateway', () => {\n  let mockPaymentService: jest.Mocked<PaymentService>;\n\n  beforeEach(() => {\n    mockPaymentService = {\n      processPayment: jest.fn(),\n    } as any;\n    \n    // The critical missing piece the AI ignored:\n    (ServiceLocator.getInstance as jest.Mock).mockReturnValue({\n      paymentService: mockPaymentService\n    });\n  });\n\n  it('should handle declined cards', async () => {\n    mockPaymentService.processPayment.mockRejectedValue(new Error('Card Declined'));\n    // ... rest of the test\n  });\n});\n```\n\nIf you're hitting a wall where the AI keeps giving you the same broken code, stop prompting for the solution. Prompt for the *assumption*. Ask: \"What do you believe is the current state of the variable X at line Y?\" Usually, you'll find the AI is hallucinating a version of your architecture that doesn't exist.\n\n## Stop guessing and use a shared knowledge base\n\nDoing this alone is a slog. I realized that while I was fighting this singleton bug, someone in the PromptCube community had already documented a similar struggle with the same model and the same architecture pattern.\n\nThe value of an AI learning community isn't just \"getting prompts\"; it's finding the people who have already failed in the specific way you are currently failing. When you're deep in [AI Coding](/en/category/aicoding/), you realize that 80% of the struggle is context management. Knowing how to structure your files so the AI doesn't hallucinate your dependency tree is a skill you don't learn from a documentation page—you learn it from other devs who have spent four hours on a Tuesday fighting a `TypeError`.\n\n## Improving the generation workflow\n\nTo stop this from happening again, I changed my entire approach to generating tests. I no longer ask for \"unit tests for this file.\" I now provide a \"Mocking Guide\" as a `.md` file in my project root and reference it in every prompt.\n\nMy new [Workflows](/en/category/workflows/) for testing look like this:\n\n1. Attach the target file.\n\n2. Attach the `MOCKING_GUIDE.md` (which explains the singleton pattern).\n\n3. Command: \"Generate tests following the mocking patterns defined in MOCKING_GUIDE.md.\"\n\nThe result? The failure rate of generated tests dropped from about 60% (mostly mock-related errors) to under 10%.\n\nIf you're tired of the \"apology loop\" where the AI says \"I apologize for the mistake\" and then repeats the mistake, you need to move beyond basic prompting. Joining a community like PromptCube gives you access to these battle-tested patterns and a place to dump your failure logs so others don't repeat them. You can join by visiting the site and diving into the forums—it's where the actual, non-marketing-speak implementation details live.\n\n[Next DeepSeek v4 and Gemini 1.5 both failed to fix my ESP-IDF component paths →](/en/threads/9266/)", "url": "https://wpnews.pro/news/solving-the-hallucination-loop-in-ai-generated-unit-tests", "canonical_source": "https://promptcube3.com/en/posts/9270/", "published_at": "2026-09-12 17:25:20+00:00", "updated_at": "2026-09-12 17:50:44.308442+00:00", "lang": "en", "topics": ["ai-tools", "developer-tools", "large-language-models", "ai-products"], "entities": ["Claude 3.5 Sonnet", "Cursor", "TypeScript", "Jest", "PaymentService", "ServiceLocator", "PromptCube"], "alternates": {"html": "https://wpnews.pro/news/solving-the-hallucination-loop-in-ai-generated-unit-tests", "markdown": "https://wpnews.pro/news/solving-the-hallucination-loop-in-ai-generated-unit-tests.md", "text": "https://wpnews.pro/news/solving-the-hallucination-loop-in-ai-generated-unit-tests.txt", "jsonld": "https://wpnews.pro/news/solving-the-hallucination-loop-in-ai-generated-unit-tests.jsonld"}}