<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Bhaumik</title>
    <description>The latest articles on DEV Community by Bhaumik (@bhaumik-viitor).</description>
    <link>https://dev.to/bhaumik-viitor</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3991913%2Fe27f3d08-cd9d-4895-8890-8c8646e43322.png</url>
      <title>DEV Community: Bhaumik</title>
      <link>https://dev.to/bhaumik-viitor</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/bhaumik-viitor"/>
    <language>en</language>
    <item>
      <title>Unit Test AI Guide — Zero Hallucination, Cross-Stack Standard</title>
      <dc:creator>Bhaumik</dc:creator>
      <pubDate>Fri, 19 Jun 2026 13:40:18 +0000</pubDate>
      <link>https://dev.to/bhaumik-viitor/unit-test-ai-guide-zero-hallucination-cross-stack-standard-4p1e</link>
      <guid>https://dev.to/bhaumik-viitor/unit-test-ai-guide-zero-hallucination-cross-stack-standard-4p1e</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Focus:&lt;/strong&gt; Unit Tests ONLY — no integration, no E2E  &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Stacks:&lt;/strong&gt; Node.js (NestJS/Express) · React.js · Python · Angular · Laravel  &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Goal:&lt;/strong&gt; AI generates unit tests consistently, deterministically, without hallucination  &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;IDE:&lt;/strong&gt; Cursor (Primary) + Claude (Secondary)&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  Part 1 — Best Single Library Per Stack (Final Decision)
&lt;/h2&gt;

&lt;p&gt;Do not mix libraries. Pick one per stack, configure it fully, never deviate.&lt;/p&gt;

&lt;p&gt;| Stack | Library | Why This One |&lt;/p&gt;

&lt;p&gt;|---|---|---|&lt;/p&gt;

&lt;p&gt;| &lt;strong&gt;Node.js / NestJS / Express&lt;/strong&gt; | &lt;code&gt;Jest&lt;/code&gt; | Native DI mocking, &lt;code&gt;@nestjs/testing&lt;/code&gt; built around it, widest ecosystem |&lt;/p&gt;

&lt;p&gt;| &lt;strong&gt;React.js&lt;/strong&gt; | &lt;code&gt;Vitest&lt;/code&gt; + &lt;code&gt;@testing-library/react&lt;/code&gt; | Native Vite/ESM support, Jest-compatible API, 3–10x faster |&lt;/p&gt;

&lt;p&gt;| &lt;strong&gt;Python&lt;/strong&gt; | &lt;code&gt;pytest&lt;/code&gt; | De facto standard, fixture system eliminates boilerplate, best plugin ecosystem |&lt;/p&gt;

&lt;p&gt;| &lt;strong&gt;Angular&lt;/strong&gt; | &lt;code&gt;Jest&lt;/code&gt; (replace Karma) | Karma is deprecated in Angular 17+; Jest is the official migration target |&lt;/p&gt;

&lt;p&gt;| &lt;strong&gt;Laravel&lt;/strong&gt; | &lt;code&gt;Pest&lt;/code&gt; | Modern syntax, built on PHPUnit, higher signal-to-noise ratio |&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Rule:&lt;/strong&gt; If someone suggests a second library for the same stack, reject it. One library per stack, configured once, followed always.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  Part 2 — IDE: Cursor (Only Choice for This Goal)
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Why Cursor and Not VS Code / WebStorm
&lt;/h3&gt;

&lt;p&gt;| Capability | Cursor | VS Code + Copilot | WebStorm |&lt;/p&gt;

&lt;p&gt;|---|---|---|---|&lt;/p&gt;

&lt;p&gt;| Project-level AI rules | ✅ &lt;code&gt;.cursor/rules/&lt;/code&gt; | ❌ | ❌ |&lt;/p&gt;

&lt;p&gt;| Codebase-aware context | ✅ &lt;code&gt;@codebase&lt;/code&gt; | Partial | Partial |&lt;/p&gt;

&lt;p&gt;| Run terminal + read output | ✅ Composer | ❌ | ❌ |&lt;/p&gt;

&lt;p&gt;| Multi-file generation | ✅ Agent mode | Limited | ❌ |&lt;/p&gt;

&lt;p&gt;| Custom instructions per filetype | ✅ | ❌ | ❌ |&lt;/p&gt;

&lt;p&gt;| MCP server integration | ✅ | ❌ | ❌ |&lt;/p&gt;

&lt;p&gt;Cursor's &lt;code&gt;.cursor/rules/&lt;/code&gt; system is the &lt;strong&gt;only IDE-native mechanism&lt;/strong&gt; that injects persistent, project-scoped instructions into every AI interaction — this is what prevents hallucination at the source.&lt;/p&gt;

&lt;h3&gt;
  
  
  Cursor Setup for This Project
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

project-root/


├── .cursor/


│   └── rules/


│       ├── unit-test-global.mdc       ← applies to all files


│       ├── unit-test-nestjs.mdc       ← applies to *.service.ts, *.guard.ts


│       ├── unit-test-react.mdc        ← applies to *.tsx, *.component.tsx


│       ├── unit-test-python.mdc       ← applies to *.py


│       ├── unit-test-angular.mdc      ← applies to *.component.ts, *.service.ts


│       └── unit-test-laravel.mdc      ← applies to *Service.php, *Model.php


├── CLAUDE.md                          ← Claude project memory file


└── ...


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Part 3 — Cursor Rules Files (Anti-Hallucination Core)
&lt;/h2&gt;

&lt;p&gt;These files are injected into every AI prompt automatically when working on matching files.&lt;/p&gt;

&lt;h3&gt;
  
  
  3.1 Global Unit Test Rule
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;File: &lt;code&gt;.cursor/rules/unit-test-global.mdc&lt;/code&gt;&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight markdown"&gt;&lt;code&gt;&lt;span class="p"&gt;

---

&lt;/span&gt;
description: Global unit test rules — applies to all files in this project&lt;span class="sb"&gt;


&lt;/span&gt;globs: ["&lt;span class="gs"&gt;**/*.spec.ts", "**&lt;/span&gt;/&lt;span class="ge"&gt;*.test.ts", "**/*&lt;/span&gt;.spec.tsx", "&lt;span class="gs"&gt;**/*_test.py", "**&lt;/span&gt;/Test&lt;span class="err"&gt;*&lt;/span&gt;.php"]&lt;span class="sb"&gt;


&lt;/span&gt;alwaysApply: true&lt;span class="sb"&gt;


&lt;/span&gt;&lt;span class="p"&gt;---




&lt;/span&gt;
&lt;span class="gh"&gt;# Unit Test Contract — MUST FOLLOW, NO EXCEPTIONS&lt;/span&gt;&lt;span class="sb"&gt;





&lt;/span&gt;&lt;span class="gu"&gt;## What is a unit test here&lt;/span&gt;&lt;span class="sb"&gt;


&lt;/span&gt;&lt;span class="p"&gt;-&lt;/span&gt; Tests ONE class or function in complete isolation&lt;span class="sb"&gt;


&lt;/span&gt;&lt;span class="p"&gt;-&lt;/span&gt; ALL external dependencies are mocked — no real DB, no real HTTP, no real file system&lt;span class="sb"&gt;


&lt;/span&gt;&lt;span class="p"&gt;-&lt;/span&gt; Each test runs independently — no shared mutable state between tests&lt;span class="sb"&gt;


&lt;/span&gt;&lt;span class="p"&gt;-&lt;/span&gt; Runs in &amp;lt; 100ms&lt;span class="sb"&gt;





&lt;/span&gt;&lt;span class="gu"&gt;## Structure: AAA — Always, Without Exception&lt;/span&gt;&lt;span class="sb"&gt;


&lt;/span&gt;Every test MUST have these three sections, with comments:&lt;span class="sb"&gt;


&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;// Arrange — set up inputs, mocks, expected values&lt;/p&gt;

&lt;p&gt;// Act — call the single function/method under test&lt;/p&gt;

&lt;p&gt;// Assert — verify exactly one outcome&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;




## Naming Convention — Mandatory


- File: `[module-name].spec.ts` or `[module-name].unit.spec.ts`


- Describe block: exact class or function name


- It/test block: "should [expected behavior] when [specific condition]"


  GOOD: "should throw NotFoundException when user does not exist"


  BAD:  "user not found", "test 1", "works correctly"





## What to test per function — minimum coverage


1. Happy path — valid input → expected output


2. Null/undefined input — how does it fail safely


3. Empty input — empty string, empty array, zero


4. Error path — when dependency throws, what happens


5. Boundary — max length, negative numbers, boolean edge





## What NOT to include in unit tests


- Database queries (mock the repository)


- HTTP calls (mock the service/axios/fetch)


- File system operations (mock fs)


- Timer behavior (use jest.useFakeTimers)


- Random values (mock Math.random or faker with fixed seed)





## AI Instruction


When asked to generate a unit test:


1. READ the function signature and types first


2. IDENTIFY all dependencies (constructor args, imported modules)


3. MOCK every dependency — never use real implementations


4. Generate minimum 4 test cases per method (happy, null, error, edge)


5. NEVER import from test doubles or assume what isn't in the source file


6. If you are unsure of a type — ASK, do not assume


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h3&gt;
  
  
  3.2 NestJS Rule
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;File: &lt;code&gt;.cursor/rules/unit-test-nestjs.mdc&lt;/code&gt;&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight markdown"&gt;&lt;code&gt;&lt;span class="p"&gt;

---

&lt;/span&gt;
description: NestJS unit test rules&lt;span class="sb"&gt;


&lt;/span&gt;globs: ["src/&lt;span class="gs"&gt;**/*.service.ts", "src/**&lt;/span&gt;/&lt;span class="ge"&gt;*.guard.ts", "src/**/*&lt;/span&gt;.interceptor.ts", "src/&lt;span class="ge"&gt;**&lt;/span&gt;/&lt;span class="err"&gt;*&lt;/span&gt;.pipe.ts"]&lt;span class="sb"&gt;


&lt;/span&gt;&lt;span class="p"&gt;---




&lt;/span&gt;
&lt;span class="gh"&gt;# NestJS Unit Test Rules&lt;/span&gt;&lt;span class="sb"&gt;





&lt;/span&gt;&lt;span class="gu"&gt;## Library: Jest + @nestjs/testing + jest-mock-extended&lt;/span&gt;&lt;span class="sb"&gt;





&lt;/span&gt;&lt;span class="gu"&gt;## Always use Test.createTestingModule&lt;/span&gt;&lt;span class="sb"&gt;


&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;&lt;br&gt;
typescript&lt;/p&gt;

&lt;p&gt;const module = await Test.createTestingModule({&lt;/p&gt;

&lt;p&gt;providers: [&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;SubjectService,


{ provide: DependencyService, useValue: mockDependency }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;p&gt;]&lt;/p&gt;

&lt;p&gt;}).compile();&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;




## Mock Pattern — jest-mock-extended


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;&lt;br&gt;
typescript&lt;/p&gt;

&lt;p&gt;import { createMock } from '@golevelup/ts-jest';&lt;/p&gt;

&lt;p&gt;// OR&lt;/p&gt;

&lt;p&gt;import { mock } from 'jest-mock-extended';&lt;/p&gt;

&lt;p&gt;const mockUserRepo = mock();&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;




## Never


- Never use `new SubjectService()` directly — always use TestingModule


- Never let `useValue` contain real implementations


- Never test more than one service per describe block





## Repository Mock Template


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;&lt;br&gt;
typescript&lt;/p&gt;

&lt;p&gt;const mockRepo = {&lt;/p&gt;

&lt;p&gt;findOne: jest.fn(),&lt;/p&gt;

&lt;p&gt;save: jest.fn(),&lt;/p&gt;

&lt;p&gt;delete: jest.fn(),&lt;/p&gt;

&lt;p&gt;findAll: jest.fn(),&lt;/p&gt;

&lt;p&gt;update: jest.fn(),&lt;/p&gt;

&lt;p&gt;};&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;




## Required imports for every NestJS spec file


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;&lt;br&gt;
typescript&lt;/p&gt;

&lt;p&gt;import { Test, TestingModule } from '@nestjs/testing';&lt;/p&gt;

&lt;p&gt;import { NotFoundException, BadRequestException } from '@nestjs/common';&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;&lt;br&gt;
markdown&lt;/p&gt;


&lt;h3&gt;
  
  
  3.3 React Rule
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;File: &lt;code&gt;.cursor/rules/unit-test-react.mdc&lt;/code&gt;&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight markdown"&gt;&lt;code&gt;&lt;span class="p"&gt;

---

&lt;/span&gt;
description: React unit test rules&lt;span class="sb"&gt;


&lt;/span&gt;globs: ["src/&lt;span class="gs"&gt;**/*.tsx", "src/**&lt;/span&gt;/&lt;span class="ge"&gt;*.component.tsx", "src/hooks/**/*&lt;/span&gt;.ts"]&lt;span class="sb"&gt;


&lt;/span&gt;&lt;span class="p"&gt;---




&lt;/span&gt;
&lt;span class="gh"&gt;# React Unit Test Rules&lt;/span&gt;&lt;span class="sb"&gt;





&lt;/span&gt;&lt;span class="gu"&gt;## Library: Vitest + @testing-library/react + @testing-library/user-event&lt;/span&gt;&lt;span class="sb"&gt;





&lt;/span&gt;&lt;span class="gu"&gt;## Required setup in vitest.config.ts&lt;/span&gt;&lt;span class="sb"&gt;


&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;&lt;br&gt;
typescript&lt;/p&gt;

&lt;p&gt;export default defineConfig({&lt;/p&gt;

&lt;p&gt;test: {&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;environment: 'jsdom',


globals: true,


setupFiles: ['./src/test/setup.ts']
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;p&gt;}&lt;/p&gt;

&lt;p&gt;})&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;




## setup.ts


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;&lt;br&gt;
typescript&lt;/p&gt;

&lt;p&gt;import '@testing-library/jest-dom';&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;




## Component test structure


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;&lt;br&gt;
typescript&lt;/p&gt;

&lt;p&gt;import { render, screen } from '@testing-library/react';&lt;/p&gt;

&lt;p&gt;import userEvent from '@testing-library/user-event';&lt;/p&gt;

&lt;p&gt;import { vi } from 'vitest';&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;




## Mocking rules for React


- Mock ALL hooks that call APIs: `vi.mock('../hooks/useUsers')`


- Mock ALL context providers — wrap with test-specific providers


- Mock router: use `MemoryRouter` from react-router-dom


- NEVER mock internal state (useState) — test behavior, not implementation





## Query priority (RTL best practice — mandatory)


1. getByRole — prefer always


2. getByLabelText — for forms


3. getByText — for content


4. getByTestId — LAST RESORT only, requires data-testid attribute





## User event — always use userEvent, never fireEvent


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;&lt;br&gt;
typescript&lt;/p&gt;

&lt;p&gt;const user = userEvent.setup();&lt;/p&gt;

&lt;p&gt;await user.click(button);&lt;/p&gt;

&lt;p&gt;await user.type(input, 'value');&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;




## Custom hook testing


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;&lt;br&gt;
typescript&lt;/p&gt;

&lt;p&gt;import { renderHook, act } from '@testing-library/react';&lt;/p&gt;

&lt;p&gt;const { result } = renderHook(() =&amp;gt; useMyHook());&lt;/p&gt;

&lt;p&gt;act(() =&amp;gt; result.current.doSomething());&lt;/p&gt;

&lt;p&gt;expect(result.current.value).toBe('expected');&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;&lt;br&gt;
typescript&lt;/p&gt;


&lt;h3&gt;
  
  
  3.4 Python Rule
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;File: &lt;code&gt;.cursor/rules/unit-test-python.mdc&lt;/code&gt;&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight markdown"&gt;&lt;code&gt;&lt;span class="p"&gt;

---

&lt;/span&gt;
description: Python unit test rules&lt;span class="sb"&gt;


&lt;/span&gt;globs: ["&lt;span class="gs"&gt;**/*.py", "!**&lt;/span&gt;/&lt;span class="ge"&gt;*migrations*&lt;/span&gt;"]&lt;span class="sb"&gt;


&lt;/span&gt;&lt;span class="p"&gt;---




&lt;/span&gt;
&lt;span class="gh"&gt;# Python Unit Test Rules&lt;/span&gt;&lt;span class="sb"&gt;





&lt;/span&gt;&lt;span class="gu"&gt;## Library: pytest + pytest-mock + factory-boy&lt;/span&gt;&lt;span class="sb"&gt;





&lt;/span&gt;&lt;span class="gu"&gt;## File naming&lt;/span&gt;&lt;span class="sb"&gt;


&lt;/span&gt;&lt;span class="p"&gt;-&lt;/span&gt; Source: &lt;span class="sb"&gt;`app/services/user_service.py`


&lt;/span&gt;&lt;span class="p"&gt;-&lt;/span&gt; Test:   &lt;span class="sb"&gt;`tests/unit/test_user_service.py`


&lt;/span&gt;&lt;span class="p"&gt;-&lt;/span&gt; ALWAYS mirror the source directory structure under tests/unit/&lt;span class="sb"&gt;





&lt;/span&gt;&lt;span class="gu"&gt;## Class under test — always use dependency injection&lt;/span&gt;&lt;span class="sb"&gt;


&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;&lt;br&gt;
python&lt;/p&gt;
&lt;h1&gt;
  
  
  GOOD — injectable dependency
&lt;/h1&gt;

&lt;p&gt;class UserService:&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;def __init__(self, repo: UserRepository):


    self.repo = repo
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;h1&gt;
  
  
  BAD — untestable
&lt;/h1&gt;

&lt;p&gt;class UserService:&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;def __init__(self):


    self.repo = UserRepository()  # can't mock this
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;




## Mock pattern — pytest-mock (mocker fixture)


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;p&gt;&lt;br&gt;
python&lt;/p&gt;

&lt;p&gt;def test_raises_when_user_not_found(mocker):&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;mock_repo = mocker.Mock()


mock_repo.find_by_id.return_value = None


service = UserService(mock_repo)


with pytest.raises(UserNotFoundException):


    service.get_user("missing-id")
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;




## Async tests — pytest-asyncio


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;p&gt;&lt;br&gt;
python&lt;/p&gt;

&lt;p&gt;import pytest&lt;/p&gt;

&lt;p&gt;@pytest.mark.asyncio&lt;/p&gt;

&lt;p&gt;async def test_async_service(mocker):&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;mock_repo = mocker.AsyncMock()


...
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;




## Fixture pattern — for shared setup


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;p&gt;&lt;br&gt;
python&lt;/p&gt;

&lt;p&gt;@pytest.fixture&lt;/p&gt;

&lt;p&gt;def user_service(mocker):&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;repo = mocker.Mock()


return UserService(repo), repo
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;p&gt;def test_get_user_happy_path(user_service):&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;service, repo = user_service


repo.find_by_id.return_value = User(id="1", email="a@b.com")


result = service.get_user("1")


assert result.email == "a@b.com"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;




## Naming


- File: `test_[module_name].py`


- Function: `test_[expected_behavior]_when_[condition]`


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;p&gt;&lt;br&gt;
markdown&lt;/p&gt;


&lt;h3&gt;
  
  
  3.5 Angular Rule
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;File: &lt;code&gt;.cursor/rules/unit-test-angular.mdc&lt;/code&gt;&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight markdown"&gt;&lt;code&gt;&lt;span class="p"&gt;

---

&lt;/span&gt;
description: Angular unit test rules&lt;span class="sb"&gt;


&lt;/span&gt;globs: ["src/app/&lt;span class="gs"&gt;**/*.component.ts", "src/app/**&lt;/span&gt;/&lt;span class="ge"&gt;*.service.ts", "src/app/**/*&lt;/span&gt;.pipe.ts", "src/app/&lt;span class="ge"&gt;**&lt;/span&gt;/&lt;span class="err"&gt;*&lt;/span&gt;.guard.ts"]&lt;span class="sb"&gt;


&lt;/span&gt;&lt;span class="p"&gt;---




&lt;/span&gt;
&lt;span class="gh"&gt;# Angular Unit Test Rules&lt;/span&gt;&lt;span class="sb"&gt;





&lt;/span&gt;&lt;span class="gu"&gt;## Library: Jest (NOT Karma — Karma is deprecated Angular 17+)&lt;/span&gt;&lt;span class="sb"&gt;





&lt;/span&gt;&lt;span class="gu"&gt;## Migration from Karma to Jest (one-time)&lt;/span&gt;&lt;span class="sb"&gt;


&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;&lt;br&gt;
bash&lt;/p&gt;

&lt;p&gt;ng add @angular-builders/jest&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;




## TestBed configuration — always minimal


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;&lt;br&gt;
typescript&lt;/p&gt;

&lt;p&gt;await TestBed.configureTestingModule({&lt;/p&gt;

&lt;p&gt;imports: [ComponentUnderTest],  // standalone components&lt;/p&gt;

&lt;p&gt;providers: [&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{ provide: UserService, useValue: mockUserService }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;p&gt;]&lt;/p&gt;

&lt;p&gt;}).compileComponents();&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;




## Service mock pattern


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;&lt;br&gt;
typescript&lt;/p&gt;

&lt;p&gt;const mockUserService = {&lt;/p&gt;

&lt;p&gt;getUser: jest.fn(),&lt;/p&gt;

&lt;p&gt;createUser: jest.fn(),&lt;/p&gt;

&lt;p&gt;};&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;




## Component test — check DOM behavior, not internal state


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;&lt;br&gt;
typescript&lt;/p&gt;

&lt;p&gt;fixture.detectChanges(); // trigger ngOnInit&lt;/p&gt;

&lt;p&gt;const button = fixture.debugElement.query(By.css('[data-testid="submit"]'));&lt;/p&gt;

&lt;p&gt;button.nativeElement.click();&lt;/p&gt;

&lt;p&gt;fixture.detectChanges();&lt;/p&gt;

&lt;p&gt;expect(fixture.debugElement.query(By.css('.error-msg'))).toBeTruthy();&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;




## Pipe test — pure function, no TestBed needed


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;&lt;br&gt;
typescript&lt;/p&gt;

&lt;p&gt;it('should transform date correctly', () =&amp;gt; {&lt;/p&gt;

&lt;p&gt;const pipe = new DateFormatPipe();&lt;/p&gt;

&lt;p&gt;expect(pipe.transform(new Date('2024-01-01'))).toBe('Jan 1, 2024');&lt;/p&gt;

&lt;p&gt;});&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;




## Guard/resolver test — inject and call directly


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;&lt;br&gt;
typescript&lt;/p&gt;

&lt;p&gt;const guard = TestBed.inject(AuthGuard);&lt;/p&gt;

&lt;p&gt;const result = await guard.canActivate(mockRoute, mockState);&lt;/p&gt;

&lt;p&gt;expect(result).toBe(false);&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;&lt;br&gt;
python&lt;/p&gt;


&lt;h3&gt;
  
  
  3.6 Laravel Rule
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;File: &lt;code&gt;.cursor/rules/unit-test-laravel.mdc&lt;/code&gt;&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight markdown"&gt;&lt;code&gt;&lt;span class="p"&gt;

---

&lt;/span&gt;
description: Laravel unit test rules&lt;span class="sb"&gt;


&lt;/span&gt;globs: ["app/Services/&lt;span class="gs"&gt;**/*.php", "app/Models/**&lt;/span&gt;/&lt;span class="ge"&gt;*.php", "app/Http/Requests/**/*&lt;/span&gt;.php", "app/Actions/&lt;span class="ge"&gt;**&lt;/span&gt;/&lt;span class="err"&gt;*&lt;/span&gt;.php"]&lt;span class="sb"&gt;


&lt;/span&gt;&lt;span class="p"&gt;---




&lt;/span&gt;
&lt;span class="gh"&gt;# Laravel Unit Test Rules&lt;/span&gt;&lt;span class="sb"&gt;





&lt;/span&gt;&lt;span class="gu"&gt;## Library: Pest (NOT PHPUnit directly — Pest wraps it with better syntax)&lt;/span&gt;&lt;span class="sb"&gt;





&lt;/span&gt;&lt;span class="gu"&gt;## File location&lt;/span&gt;&lt;span class="sb"&gt;


&lt;/span&gt;&lt;span class="p"&gt;-&lt;/span&gt; Source: &lt;span class="sb"&gt;`app/Services/UserService.php`


&lt;/span&gt;&lt;span class="p"&gt;-&lt;/span&gt; Test:   &lt;span class="sb"&gt;`tests/Unit/Services/UserServiceTest.php`





&lt;/span&gt;&lt;span class="gu"&gt;## Class under test — use constructor injection&lt;/span&gt;&lt;span class="sb"&gt;


&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;&lt;br&gt;
php&lt;/p&gt;

&lt;p&gt;class UserService {&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;public function __construct(


    private readonly UserRepositoryInterface $repo


) {}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;p&gt;}&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;




## Mock pattern — Mockery (included with Pest/PHPUnit)


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;&lt;br&gt;
php&lt;/p&gt;

&lt;p&gt;it('throws exception when user not found', function () {&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// Arrange


$repo = Mockery::mock(UserRepositoryInterface::class);


$repo-&amp;gt;shouldReceive('findById')-&amp;gt;once()-&amp;gt;andReturn(null);


$service = new UserService($repo);





// Act &amp;amp; Assert


expect(fn () =&amp;gt; $service-&amp;gt;getUser('abc'))


    -&amp;gt;toThrow(UserNotFoundException::class);
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;p&gt;});&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;




## Data provider pattern (Pest datasets)


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;&lt;br&gt;
php&lt;/p&gt;

&lt;p&gt;it('validates email format', function (string $email, bool $valid) {&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;expect(validateEmail($email))-&amp;gt;toBe($valid);
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;p&gt;})-&amp;gt;with([&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;['valid@email.com', true],


['notanemail', false],


['', false],


['@nodomain.com', false],
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;p&gt;]);&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;




## What NOT to do in unit tests


- Never call $this-&amp;gt;get() or $this-&amp;gt;post() — that is feature testing


- Never use RefreshDatabase — that is feature/integration testing


- Never resolve from service container — inject directly


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;&lt;br&gt;
markdown&lt;/p&gt;


&lt;h2&gt;
  
  
  Part 4 — CLAUDE.md (Claude Project Memory)
&lt;/h2&gt;

&lt;p&gt;Place this at project root. Claude reads it on every session automatically.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;File: &lt;code&gt;CLAUDE.md&lt;/code&gt;&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight markdown"&gt;&lt;code&gt;

&lt;span class="gh"&gt;# Project: [Your Project Name]&lt;/span&gt;&lt;span class="sb"&gt;


&lt;/span&gt;&lt;span class="gh"&gt;# Claude Unit Test Instructions&lt;/span&gt;&lt;span class="sb"&gt;





&lt;/span&gt;&lt;span class="gu"&gt;## Stack&lt;/span&gt;&lt;span class="sb"&gt;


&lt;/span&gt;&lt;span class="p"&gt;-&lt;/span&gt; Backend: NestJS + TypeScript&lt;span class="sb"&gt;


&lt;/span&gt;&lt;span class="p"&gt;-&lt;/span&gt; Frontend: React + Vite + TypeScript&lt;span class="sb"&gt;


&lt;/span&gt;&lt;span class="p"&gt;-&lt;/span&gt; Testing: Jest (NestJS) + Vitest (React) + Pest (Laravel) + pytest (Python)&lt;span class="sb"&gt;





&lt;/span&gt;&lt;span class="gu"&gt;## Unit Test Rules — NON-NEGOTIABLE&lt;/span&gt;&lt;span class="sb"&gt;





&lt;/span&gt;&lt;span class="gu"&gt;### When asked to generate a unit test:&lt;/span&gt;&lt;span class="sb"&gt;


&lt;/span&gt;&lt;span class="p"&gt;1.&lt;/span&gt; NEVER generate integration or E2E tests unless explicitly asked&lt;span class="sb"&gt;


&lt;/span&gt;&lt;span class="p"&gt;2.&lt;/span&gt; ALWAYS mock every external dependency&lt;span class="sb"&gt;


&lt;/span&gt;&lt;span class="p"&gt;3.&lt;/span&gt; ALWAYS follow AAA (Arrange-Act-Assert) with comments&lt;span class="sb"&gt;


&lt;/span&gt;&lt;span class="p"&gt;4.&lt;/span&gt; ALWAYS generate minimum 4 cases: happy path, null/empty, error thrown, edge case&lt;span class="sb"&gt;


&lt;/span&gt;&lt;span class="p"&gt;5.&lt;/span&gt; NEVER use &lt;span class="sb"&gt;`any`&lt;/span&gt; type in TypeScript tests&lt;span class="sb"&gt;


&lt;/span&gt;&lt;span class="p"&gt;6.&lt;/span&gt; NEVER leave &lt;span class="sb"&gt;`TODO`&lt;/span&gt; comments in generated tests&lt;span class="sb"&gt;





&lt;/span&gt;&lt;span class="gu"&gt;### Naming&lt;/span&gt;&lt;span class="sb"&gt;


&lt;/span&gt;&lt;span class="p"&gt;-&lt;/span&gt; NestJS: &lt;span class="sb"&gt;`[name].service.spec.ts`&lt;/span&gt; inside same directory as source&lt;span class="sb"&gt;


&lt;/span&gt;&lt;span class="p"&gt;-&lt;/span&gt; React: &lt;span class="sb"&gt;`[ComponentName].test.tsx`&lt;/span&gt; inside &lt;span class="sb"&gt;`__tests__/`&lt;/span&gt; or same directory&lt;span class="sb"&gt;


&lt;/span&gt;&lt;span class="p"&gt;-&lt;/span&gt; Python: &lt;span class="sb"&gt;`test_[module].py`&lt;/span&gt; under &lt;span class="sb"&gt;`tests/unit/`


&lt;/span&gt;&lt;span class="p"&gt;-&lt;/span&gt; Laravel: &lt;span class="sb"&gt;`[Name]Test.php`&lt;/span&gt; under &lt;span class="sb"&gt;`tests/Unit/`





&lt;/span&gt;&lt;span class="gu"&gt;### Test should describe BEHAVIOR, not implementation&lt;/span&gt;&lt;span class="sb"&gt;


&lt;/span&gt;GOOD: "should return empty array when no users match search"&lt;span class="sb"&gt;


&lt;/span&gt;BAD: "test getUserByFilter"&lt;span class="sb"&gt;





&lt;/span&gt;&lt;span class="gu"&gt;### If you are unsure of the correct mock structure:&lt;/span&gt;&lt;span class="sb"&gt;


&lt;/span&gt;&lt;span class="p"&gt;-&lt;/span&gt; Ask what the dependency interface looks like&lt;span class="sb"&gt;


&lt;/span&gt;&lt;span class="p"&gt;-&lt;/span&gt; Do NOT invent method names that don't exist in the source&lt;span class="sb"&gt;





&lt;/span&gt;&lt;span class="gu"&gt;### Coverage target: 80% lines, 75% branches per module&lt;/span&gt;&lt;span class="sb"&gt;





&lt;/span&gt;&lt;span class="gu"&gt;## Project Structure Reference&lt;/span&gt;&lt;span class="sb"&gt;


&lt;/span&gt;src/&lt;span class="sb"&gt;


&lt;/span&gt;  modules/&lt;span class="sb"&gt;


    users/


      users.service.ts


      users.service.spec.ts   ← unit test lives here


      users.repository.ts


      users.repository.spec.ts


&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Part 5 — MCP Servers for Unit Testing in Cursor + Claude
&lt;/h2&gt;

&lt;p&gt;MCP (Model Context Protocol) servers extend AI capabilities. For unit testing, these are the relevant ones:&lt;/p&gt;

&lt;h3&gt;
  
  
  5.1 Filesystem MCP (Built-in Cursor — use directly)
&lt;/h3&gt;

&lt;p&gt;Cursor already has filesystem access. No extra MCP needed to read source files and generate tests. The &lt;code&gt;.cursor/rules/&lt;/code&gt; system handles this.&lt;/p&gt;

&lt;h3&gt;
  
  
  5.2 Available MCP Servers for Testing Workflows
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;1. &lt;code&gt;@executeautomation/playwright-mcp-server&lt;/code&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Scope: E2E only — not relevant for unit tests&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Skip for this use case&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;2. &lt;code&gt;@modelcontextprotocol/server-filesystem&lt;/code&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Gives Claude access to project files&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Use in Claude Desktop to read source → generate tests&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Install: configured in &lt;code&gt;claude_desktop_config.json&lt;/code&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;3. Custom Testing MCP (Build This — Highest Value)&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Build a lightweight MCP server that:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Reads a source file&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Extracts function signatures + types&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Returns structured JSON to Claude&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Claude generates tests from structure, not guesswork&lt;br&gt;
&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;

&lt;span class="c1"&gt;// mcp-test-generator/src/index.ts&lt;/span&gt;


&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;Server&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@modelcontextprotocol/sdk/server/index.js&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;


&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;StdioServerTransport&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@modelcontextprotocol/sdk/server/stdio.js&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;


&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nx"&gt;ts&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;typescript&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;





&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;server&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Server&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;test-generator&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;version&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;1.0.0&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;


  &lt;span class="na"&gt;capabilities&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;tools&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;


&lt;span class="p"&gt;});&lt;/span&gt;





&lt;span class="nx"&gt;server&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setRequestHandler&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;tools/call&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;


  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;params&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;extract_signatures&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;


    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;filePath&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;params&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;arguments&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;


    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;signatures&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;extractFunctionSignatures&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;filePath&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// parse AST&lt;/span&gt;


    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;content&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[{&lt;/span&gt; &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;text&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;text&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;stringify&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;signatures&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;}]&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;


  &lt;span class="p"&gt;}&lt;/span&gt;


&lt;span class="p"&gt;});&lt;/span&gt;





&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;extractFunctionSignatures&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;filePath&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;


  &lt;span class="c1"&gt;// Use TypeScript compiler API to extract:&lt;/span&gt;


  &lt;span class="c1"&gt;// - class name&lt;/span&gt;


  &lt;span class="c1"&gt;// - method names&lt;/span&gt;


  &lt;span class="c1"&gt;// - parameter types&lt;/span&gt;


  &lt;span class="c1"&gt;// - return types&lt;/span&gt;


  &lt;span class="c1"&gt;// - injected dependencies (constructor params)&lt;/span&gt;


  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;program&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;ts&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;createProgram&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="nx"&gt;filePath&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="p"&gt;{});&lt;/span&gt;


  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;sourceFile&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;program&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getSourceFile&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;filePath&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;


  &lt;span class="c1"&gt;// ... AST traversal&lt;/span&gt;


  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;className&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;methods&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;dependencies&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;


&lt;span class="p"&gt;}&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Why this matters:&lt;/strong&gt; When Claude receives typed signatures instead of raw source code, it cannot hallucinate — it generates tests from concrete types, not guesses.&lt;/p&gt;

&lt;h3&gt;
  
  
  5.3 Claude Desktop MCP Config
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="err"&gt;//&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;~/Library/Application&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;Support/Claude/claude_desktop_config.json&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;(macOS)&lt;/span&gt;&lt;span class="w"&gt;


&lt;/span&gt;&lt;span class="err"&gt;//&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;%APPDATA%\Claude\claude_desktop_config.json&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;(Windows)&lt;/span&gt;&lt;span class="w"&gt;


&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;


  &lt;/span&gt;&lt;span class="nl"&gt;"mcpServers"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;


    &lt;/span&gt;&lt;span class="nl"&gt;"filesystem"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;


      &lt;/span&gt;&lt;span class="nl"&gt;"command"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"npx"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;


      &lt;/span&gt;&lt;span class="nl"&gt;"args"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"-y"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"@modelcontextprotocol/server-filesystem"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"/path/to/your/project"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;


    &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;


    &lt;/span&gt;&lt;span class="nl"&gt;"test-generator"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;


      &lt;/span&gt;&lt;span class="nl"&gt;"command"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"node"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;


      &lt;/span&gt;&lt;span class="nl"&gt;"args"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"/path/to/your/mcp-test-generator/dist/index.js"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;


    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;


  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;


&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;


&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  5.4 Cursor MCP Config
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="err"&gt;//&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;.cursor/mcp.json&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;(project-level)&lt;/span&gt;&lt;span class="w"&gt;


&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;


  &lt;/span&gt;&lt;span class="nl"&gt;"mcpServers"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;


    &lt;/span&gt;&lt;span class="nl"&gt;"test-generator"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;


      &lt;/span&gt;&lt;span class="nl"&gt;"command"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"node"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;


      &lt;/span&gt;&lt;span class="nl"&gt;"args"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"./tools/mcp-test-generator/dist/index.js"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;


    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;


  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;


&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;


&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Part 6 — Anti-Hallucination Prompt Templates
&lt;/h2&gt;

&lt;p&gt;The root cause of AI hallucination in tests: AI invents method names, wrong mock structures, non-existent imports. These prompts eliminate that.&lt;/p&gt;

&lt;h3&gt;
  
  
  6.1 Cursor Cmd+K Prompt (Use This Exactly)
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;

Generate a unit &lt;span class="nb"&gt;test &lt;/span&gt;file &lt;span class="k"&gt;for &lt;/span&gt;this &lt;span class="o"&gt;[&lt;/span&gt;NestJS service / React component / Python class / Angular service / Laravel service].





Rules:


- Library: &lt;span class="o"&gt;[&lt;/span&gt;Jest / Vitest / pytest / Jest / Pest]


- Test only THIS file — no integration


- Mock ALL dependencies listed &lt;span class="k"&gt;in &lt;/span&gt;the constructor/props


- Follow AAA pattern with comments


- Minimum 4 &lt;span class="nb"&gt;test &lt;/span&gt;cases per public method


- Use ONLY methods/properties that exist &lt;span class="k"&gt;in &lt;/span&gt;this &lt;span class="nb"&gt;source &lt;/span&gt;file


- Do NOT import anything not shown &lt;span class="k"&gt;in &lt;/span&gt;the &lt;span class="nb"&gt;source&lt;/span&gt;


- Naming: &lt;span class="s2"&gt;"should [behavior] when [condition]"&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  6.2 Claude Prompt (For CLAUDE.md aware sessions)
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight markdown"&gt;&lt;code&gt;

Read [filename].&lt;span class="sb"&gt;


&lt;/span&gt;Extract:&lt;span class="sb"&gt;


&lt;/span&gt;&lt;span class="p"&gt;1.&lt;/span&gt; Class/function name&lt;span class="sb"&gt;


&lt;/span&gt;&lt;span class="p"&gt;2.&lt;/span&gt; All public methods with parameter types and return types&lt;span class="sb"&gt;


&lt;/span&gt;&lt;span class="p"&gt;3.&lt;/span&gt; All constructor dependencies (for mocking)&lt;span class="sb"&gt;





&lt;/span&gt;Then generate the unit test file following CLAUDE.md rules.&lt;span class="sb"&gt;


&lt;/span&gt;Do NOT assume any method exists unless you can see it in the source.&lt;span class="sb"&gt;


&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  6.3 Batch Test Generation Prompt
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;

&lt;span class="k"&gt;For&lt;/span&gt; &lt;span class="n"&gt;each&lt;/span&gt; &lt;span class="n"&gt;file&lt;/span&gt; &lt;span class="n"&gt;in&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;directory&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="n"&gt;generate&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="n"&gt;corresponding&lt;/span&gt; &lt;span class="mf"&gt;.&lt;/span&gt;&lt;span class="n"&gt;spec&lt;/span&gt;&lt;span class="mf"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ts&lt;/span&gt; &lt;span class="n"&gt;file&lt;/span&gt;&lt;span class="mf"&gt;.&lt;/span&gt;


&lt;span class="nc"&gt;Process&lt;/span&gt; &lt;span class="n"&gt;one&lt;/span&gt; &lt;span class="n"&gt;file&lt;/span&gt; &lt;span class="n"&gt;at&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="mf"&gt;.&lt;/span&gt;


&lt;span class="k"&gt;For&lt;/span&gt; &lt;span class="n"&gt;each&lt;/span&gt; &lt;span class="n"&gt;file&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;


  &lt;span class="mf"&gt;1.&lt;/span&gt; &lt;span class="nc"&gt;Read&lt;/span&gt; &lt;span class="n"&gt;the&lt;/span&gt; &lt;span class="n"&gt;source&lt;/span&gt;


  &lt;span class="mf"&gt;2.&lt;/span&gt; &lt;span class="k"&gt;List&lt;/span&gt; &lt;span class="n"&gt;the&lt;/span&gt; &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;methods&lt;/span&gt; &lt;span class="n"&gt;you&lt;/span&gt; &lt;span class="nf"&gt;found&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;confirm&lt;/span&gt; &lt;span class="n"&gt;before&lt;/span&gt; &lt;span class="n"&gt;generating&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;


  &lt;span class="mf"&gt;3.&lt;/span&gt; &lt;span class="nc"&gt;Generate&lt;/span&gt; &lt;span class="n"&gt;the&lt;/span&gt; &lt;span class="n"&gt;test&lt;/span&gt; &lt;span class="n"&gt;file&lt;/span&gt;


  &lt;span class="mf"&gt;4.&lt;/span&gt; &lt;span class="nc"&gt;Show&lt;/span&gt; &lt;span class="n"&gt;the&lt;/span&gt; &lt;span class="n"&gt;test&lt;/span&gt; &lt;span class="n"&gt;file&lt;/span&gt; &lt;span class="n"&gt;path&lt;/span&gt;





&lt;span class="k"&gt;Do&lt;/span&gt; &lt;span class="n"&gt;not&lt;/span&gt; &lt;span class="n"&gt;proceed&lt;/span&gt; &lt;span class="n"&gt;to&lt;/span&gt; &lt;span class="n"&gt;the&lt;/span&gt; &lt;span class="n"&gt;next&lt;/span&gt; &lt;span class="n"&gt;file&lt;/span&gt; &lt;span class="n"&gt;until&lt;/span&gt; &lt;span class="n"&gt;the&lt;/span&gt; &lt;span class="n"&gt;current&lt;/span&gt; &lt;span class="n"&gt;one&lt;/span&gt; &lt;span class="n"&gt;is&lt;/span&gt; &lt;span class="n"&gt;confirmed&lt;/span&gt;&lt;span class="mf"&gt;.&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Part 7 — Project Structure Convention
&lt;/h2&gt;

&lt;p&gt;All stacks follow the same proximity principle: &lt;strong&gt;test file lives next to source file&lt;/strong&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Node.js / NestJS / Angular
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight markdown"&gt;&lt;code&gt;

src/&lt;span class="sb"&gt;


&lt;/span&gt;  modules/&lt;span class="sb"&gt;


    users/


      users.service.ts


      users.service.spec.ts        ← unit test


      users.repository.ts


      users.repository.spec.ts     ← unit test


      users.guard.ts


      users.guard.spec.ts          ← unit test


&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  React
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

src/


  components/


    UserCard/


      UserCard.tsx


      UserCard.test.tsx            ← unit test


      UserCard.stories.tsx         ← storybook (optional)


  hooks/


    useUserData.ts


    useUserData.test.ts            ← unit test


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Python
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

app/


  services/


    user_service.py


tests/


  unit/


    services/


      test_user_service.py        ← mirrors app/ structure


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Laravel
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

app/


  Services/


    UserService.php


tests/


  Unit/


    Services/


      UserServiceTest.php         ← mirrors app/ structure


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Part 8 — CI Enforcement
&lt;/h2&gt;

&lt;p&gt;All of this means nothing without enforcement. The pipeline is the final gate.&lt;/p&gt;

&lt;h3&gt;
  
  
  GitHub Actions — Multi-stack parallel
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;

&lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Unit Tests&lt;/span&gt;





&lt;span class="na"&gt;on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;push&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;pull_request&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;





&lt;span class="na"&gt;jobs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;


  &lt;span class="na"&gt;nestjs-unit&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;


    &lt;span class="na"&gt;runs-on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;ubuntu-latest&lt;/span&gt;


    &lt;span class="na"&gt;steps&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;


      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;actions/checkout@v4&lt;/span&gt;


      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;actions/setup-node@v4&lt;/span&gt;


        &lt;span class="na"&gt;with&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;{&lt;/span&gt; &lt;span class="nv"&gt;node-version&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;20'&lt;/span&gt; &lt;span class="pi"&gt;}&lt;/span&gt;


      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;npm ci&lt;/span&gt;


      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;npm run test:unit -- --coverage --coverageThreshold='{"global":{"lines":80}}'&lt;/span&gt;





  &lt;span class="na"&gt;react-unit&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;


    &lt;span class="na"&gt;runs-on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;ubuntu-latest&lt;/span&gt;


    &lt;span class="na"&gt;steps&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;


      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;actions/checkout@v4&lt;/span&gt;


      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;actions/setup-node@v4&lt;/span&gt;


        &lt;span class="na"&gt;with&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;{&lt;/span&gt; &lt;span class="nv"&gt;node-version&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;20'&lt;/span&gt; &lt;span class="pi"&gt;}&lt;/span&gt;


      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;npm ci&lt;/span&gt;


      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;npx vitest run --coverage&lt;/span&gt;





  &lt;span class="na"&gt;python-unit&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;


    &lt;span class="na"&gt;runs-on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;ubuntu-latest&lt;/span&gt;


    &lt;span class="na"&gt;steps&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;


      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;actions/checkout@v4&lt;/span&gt;


      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;actions/setup-python@v5&lt;/span&gt;


        &lt;span class="na"&gt;with&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;{&lt;/span&gt; &lt;span class="nv"&gt;python-version&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;3.12'&lt;/span&gt; &lt;span class="pi"&gt;}&lt;/span&gt;


      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;pip install -r requirements-dev.txt&lt;/span&gt;


      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;pytest tests/unit/ --cov=app --cov-fail-under=80&lt;/span&gt;





  &lt;span class="na"&gt;laravel-unit&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;


    &lt;span class="na"&gt;runs-on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;ubuntu-latest&lt;/span&gt;


    &lt;span class="na"&gt;steps&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;


      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;actions/checkout@v4&lt;/span&gt;


      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;shivammathur/setup-php@v2&lt;/span&gt;


        &lt;span class="na"&gt;with&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;{&lt;/span&gt; &lt;span class="nv"&gt;php-version&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;8.3'&lt;/span&gt; &lt;span class="pi"&gt;}&lt;/span&gt;


      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;composer install&lt;/span&gt;


      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;./vendor/bin/pest --coverage --min=80&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Pre-commit Hook (Husky — Node stacks)
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="err"&gt;//&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;package.json&lt;/span&gt;&lt;span class="w"&gt;


&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;


  &lt;/span&gt;&lt;span class="nl"&gt;"lint-staged"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;


    &lt;/span&gt;&lt;span class="nl"&gt;"src/**/*.service.ts"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"jest --findRelatedTests --passWithNoTests"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;


    &lt;/span&gt;&lt;span class="nl"&gt;"src/**/*.tsx"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"vitest related --run"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;


  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;


&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;


&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Part 9 — Quick Start Checklist
&lt;/h2&gt;

&lt;h3&gt;
  
  
  New Project
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

□ Install test library (one per stack — see Part 1)


□ Configure jest.config.ts / vitest.config.ts / pytest.ini / pest.php


□ Create .cursor/rules/ directory with all rule files from Part 3


□ Create CLAUDE.md at project root from Part 4


□ Add coverage thresholds to config


□ Add pre-commit hooks (Husky for Node, pre-commit for Python)


□ Add CI workflow from Part 8


□ Create test factory files (one per major entity)


□ Write first failing test → implement → green → commit


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Existing Project
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

□ Add test library without touching existing code


□ Add .cursor/rules/ + CLAUDE.md


□ Run coverage on existing code → document current baseline


□ Pick 3 critical services → generate tests → set as new baseline


□ Add CI with threshold = current baseline (not ideal — current)


□ Raise threshold by 5% per sprint


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Appendix — Install Commands Per Stack
&lt;/h2&gt;

&lt;h3&gt;
  
  
  NestJS
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;

npm &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;--save-dev&lt;/span&gt; jest ts-jest @types/jest @nestjs/testing jest-mock-extended @golevelup/ts-jest


npx ts-jest config:init


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  React (Vite)
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;

npm &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;--save-dev&lt;/span&gt; vitest @vitest/coverage-v8 @testing-library/react @testing-library/user-event @testing-library/jest-dom jsdom


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Python
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;

pip &lt;span class="nb"&gt;install &lt;/span&gt;pytest pytest-cov pytest-mock pytest-asyncio factory-boy


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Angular
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;

ng add @angular-builders/jest


npm &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;--save-dev&lt;/span&gt; jest jest-preset-angular @types/jest


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Laravel
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;

composer require pestphp/pest pestphp/pest-plugin-laravel &lt;span class="nt"&gt;--dev&lt;/span&gt;


./vendor/bin/pest &lt;span class="nt"&gt;--init&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;p&gt;&lt;em&gt;Last updated: 2025 — verify library major versions before adopting&lt;/em&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>programming</category>
      <category>testing</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>Unit Test AI Guide — Zero Hallucination, Cross-Stack Standard</title>
      <dc:creator>Bhaumik</dc:creator>
      <pubDate>Fri, 19 Jun 2026 12:36:41 +0000</pubDate>
      <link>https://dev.to/bhaumik-viitor/unit-test-ai-guide-zero-hallucination-cross-stack-standard-5910</link>
      <guid>https://dev.to/bhaumik-viitor/unit-test-ai-guide-zero-hallucination-cross-stack-standard-5910</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Focus:&lt;/strong&gt; Unit Tests ONLY — no integration, no E2E  &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Stacks:&lt;/strong&gt; Node.js (NestJS/Express) · React.js · Python · Angular · Laravel  &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Goal:&lt;/strong&gt; AI generates unit tests consistently, deterministically, without hallucination  &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;IDE:&lt;/strong&gt; Cursor (Primary) + Claude (Secondary)&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  Part 1 — Best Single Library Per Stack (Final Decision)
&lt;/h2&gt;

&lt;p&gt;Do not mix libraries. Pick one per stack, configure it fully, never deviate.&lt;/p&gt;

&lt;p&gt;| Stack | Library | Why This One |&lt;/p&gt;

&lt;p&gt;|---|---|---|&lt;/p&gt;

&lt;p&gt;| &lt;strong&gt;Node.js / NestJS / Express&lt;/strong&gt; | &lt;code&gt;Jest&lt;/code&gt; | Native DI mocking, &lt;code&gt;@nestjs/testing&lt;/code&gt; built around it, widest ecosystem |&lt;/p&gt;

&lt;p&gt;| &lt;strong&gt;React.js&lt;/strong&gt; | &lt;code&gt;Vitest&lt;/code&gt; + &lt;code&gt;@testing-library/react&lt;/code&gt; | Native Vite/ESM support, Jest-compatible API, 3–10x faster |&lt;/p&gt;

&lt;p&gt;| &lt;strong&gt;Python&lt;/strong&gt; | &lt;code&gt;pytest&lt;/code&gt; | De facto standard, fixture system eliminates boilerplate, best plugin ecosystem |&lt;/p&gt;

&lt;p&gt;| &lt;strong&gt;Angular&lt;/strong&gt; | &lt;code&gt;Jest&lt;/code&gt; (replace Karma) | Karma is deprecated in Angular 17+; Jest is the official migration target |&lt;/p&gt;

&lt;p&gt;| &lt;strong&gt;Laravel&lt;/strong&gt; | &lt;code&gt;Pest&lt;/code&gt; | Modern syntax, built on PHPUnit, higher signal-to-noise ratio |&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Rule:&lt;/strong&gt; If someone suggests a second library for the same stack, reject it. One library per stack, configured once, followed always.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  Part 2 — IDE: Cursor (Only Choice for This Goal)
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Why Cursor and Not VS Code / WebStorm
&lt;/h3&gt;

&lt;p&gt;| Capability | Cursor | VS Code + Copilot | WebStorm |&lt;/p&gt;

&lt;p&gt;|---|---|---|---|&lt;/p&gt;

&lt;p&gt;| Project-level AI rules | ✅ &lt;code&gt;.cursor/rules/&lt;/code&gt; | ❌ | ❌ |&lt;/p&gt;

&lt;p&gt;| Codebase-aware context | ✅ &lt;code&gt;@codebase&lt;/code&gt; | Partial | Partial |&lt;/p&gt;

&lt;p&gt;| Run terminal + read output | ✅ Composer | ❌ | ❌ |&lt;/p&gt;

&lt;p&gt;| Multi-file generation | ✅ Agent mode | Limited | ❌ |&lt;/p&gt;

&lt;p&gt;| Custom instructions per filetype | ✅ | ❌ | ❌ |&lt;/p&gt;

&lt;p&gt;| MCP server integration | ✅ | ❌ | ❌ |&lt;/p&gt;

&lt;p&gt;Cursor's &lt;code&gt;.cursor/rules/&lt;/code&gt; system is the &lt;strong&gt;only IDE-native mechanism&lt;/strong&gt; that injects persistent, project-scoped instructions into every AI interaction — this is what prevents hallucination at the source.&lt;/p&gt;

&lt;h3&gt;
  
  
  Cursor Setup for This Project
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

project-root/


├── .cursor/


│   └── rules/


│       ├── unit-test-global.mdc       ← applies to all files


│       ├── unit-test-nestjs.mdc       ← applies to *.service.ts, *.guard.ts


│       ├── unit-test-react.mdc        ← applies to *.tsx, *.component.tsx


│       ├── unit-test-python.mdc       ← applies to *.py


│       ├── unit-test-angular.mdc      ← applies to *.component.ts, *.service.ts


│       └── unit-test-laravel.mdc      ← applies to *Service.php, *Model.php


├── CLAUDE.md                          ← Claude project memory file


└── ...


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Part 3 — Cursor Rules Files (Anti-Hallucination Core)
&lt;/h2&gt;

&lt;p&gt;These files are injected into every AI prompt automatically when working on matching files.&lt;/p&gt;

&lt;h3&gt;
  
  
  3.1 Global Unit Test Rule
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;File: &lt;code&gt;.cursor/rules/unit-test-global.mdc&lt;/code&gt;&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight markdown"&gt;&lt;code&gt;&lt;span class="p"&gt;

---

&lt;/span&gt;
description: Global unit test rules — applies to all files in this project&lt;span class="sb"&gt;


&lt;/span&gt;globs: ["&lt;span class="gs"&gt;**/*.spec.ts", "**&lt;/span&gt;/&lt;span class="ge"&gt;*.test.ts", "**/*&lt;/span&gt;.spec.tsx", "&lt;span class="gs"&gt;**/*_test.py", "**&lt;/span&gt;/Test&lt;span class="err"&gt;*&lt;/span&gt;.php"]&lt;span class="sb"&gt;


&lt;/span&gt;alwaysApply: true&lt;span class="sb"&gt;


&lt;/span&gt;&lt;span class="p"&gt;---




&lt;/span&gt;
&lt;span class="gh"&gt;# Unit Test Contract — MUST FOLLOW, NO EXCEPTIONS&lt;/span&gt;&lt;span class="sb"&gt;





&lt;/span&gt;&lt;span class="gu"&gt;## What is a unit test here&lt;/span&gt;&lt;span class="sb"&gt;


&lt;/span&gt;&lt;span class="p"&gt;-&lt;/span&gt; Tests ONE class or function in complete isolation&lt;span class="sb"&gt;


&lt;/span&gt;&lt;span class="p"&gt;-&lt;/span&gt; ALL external dependencies are mocked — no real DB, no real HTTP, no real file system&lt;span class="sb"&gt;


&lt;/span&gt;&lt;span class="p"&gt;-&lt;/span&gt; Each test runs independently — no shared mutable state between tests&lt;span class="sb"&gt;


&lt;/span&gt;&lt;span class="p"&gt;-&lt;/span&gt; Runs in &amp;lt; 100ms&lt;span class="sb"&gt;





&lt;/span&gt;&lt;span class="gu"&gt;## Structure: AAA — Always, Without Exception&lt;/span&gt;&lt;span class="sb"&gt;


&lt;/span&gt;Every test MUST have these three sections, with comments:&lt;span class="sb"&gt;


&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;// Arrange — set up inputs, mocks, expected values&lt;/p&gt;

&lt;p&gt;// Act — call the single function/method under test&lt;/p&gt;

&lt;p&gt;// Assert — verify exactly one outcome&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;




## Naming Convention — Mandatory


- File: `[module-name].spec.ts` or `[module-name].unit.spec.ts`


- Describe block: exact class or function name


- It/test block: "should [expected behavior] when [specific condition]"


  GOOD: "should throw NotFoundException when user does not exist"


  BAD:  "user not found", "test 1", "works correctly"





## What to test per function — minimum coverage


1. Happy path — valid input → expected output


2. Null/undefined input — how does it fail safely


3. Empty input — empty string, empty array, zero


4. Error path — when dependency throws, what happens


5. Boundary — max length, negative numbers, boolean edge





## What NOT to include in unit tests


- Database queries (mock the repository)


- HTTP calls (mock the service/axios/fetch)


- File system operations (mock fs)


- Timer behavior (use jest.useFakeTimers)


- Random values (mock Math.random or faker with fixed seed)





## AI Instruction


When asked to generate a unit test:


1. READ the function signature and types first


2. IDENTIFY all dependencies (constructor args, imported modules)


3. MOCK every dependency — never use real implementations


4. Generate minimum 4 test cases per method (happy, null, error, edge)


5. NEVER import from test doubles or assume what isn't in the source file


6. If you are unsure of a type — ASK, do not assume


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h3&gt;
  
  
  3.2 NestJS Rule
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;File: &lt;code&gt;.cursor/rules/unit-test-nestjs.mdc&lt;/code&gt;&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight markdown"&gt;&lt;code&gt;&lt;span class="p"&gt;

---

&lt;/span&gt;
description: NestJS unit test rules&lt;span class="sb"&gt;


&lt;/span&gt;globs: ["src/&lt;span class="gs"&gt;**/*.service.ts", "src/**&lt;/span&gt;/&lt;span class="ge"&gt;*.guard.ts", "src/**/*&lt;/span&gt;.interceptor.ts", "src/&lt;span class="ge"&gt;**&lt;/span&gt;/&lt;span class="err"&gt;*&lt;/span&gt;.pipe.ts"]&lt;span class="sb"&gt;


&lt;/span&gt;&lt;span class="p"&gt;---




&lt;/span&gt;
&lt;span class="gh"&gt;# NestJS Unit Test Rules&lt;/span&gt;&lt;span class="sb"&gt;





&lt;/span&gt;&lt;span class="gu"&gt;## Library: Jest + @nestjs/testing + jest-mock-extended&lt;/span&gt;&lt;span class="sb"&gt;





&lt;/span&gt;&lt;span class="gu"&gt;## Always use Test.createTestingModule&lt;/span&gt;&lt;span class="sb"&gt;


&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;&lt;br&gt;
typescript&lt;/p&gt;

&lt;p&gt;const module = await Test.createTestingModule({&lt;/p&gt;

&lt;p&gt;providers: [&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;SubjectService,


{ provide: DependencyService, useValue: mockDependency }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;p&gt;]&lt;/p&gt;

&lt;p&gt;}).compile();&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;




## Mock Pattern — jest-mock-extended


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;&lt;br&gt;
typescript&lt;/p&gt;

&lt;p&gt;import { createMock } from '@golevelup/ts-jest';&lt;/p&gt;

&lt;p&gt;// OR&lt;/p&gt;

&lt;p&gt;import { mock } from 'jest-mock-extended';&lt;/p&gt;

&lt;p&gt;const mockUserRepo = mock();&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;




## Never


- Never use `new SubjectService()` directly — always use TestingModule


- Never let `useValue` contain real implementations


- Never test more than one service per describe block





## Repository Mock Template


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;&lt;br&gt;
typescript&lt;/p&gt;

&lt;p&gt;const mockRepo = {&lt;/p&gt;

&lt;p&gt;findOne: jest.fn(),&lt;/p&gt;

&lt;p&gt;save: jest.fn(),&lt;/p&gt;

&lt;p&gt;delete: jest.fn(),&lt;/p&gt;

&lt;p&gt;findAll: jest.fn(),&lt;/p&gt;

&lt;p&gt;update: jest.fn(),&lt;/p&gt;

&lt;p&gt;};&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;




## Required imports for every NestJS spec file


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;&lt;br&gt;
typescript&lt;/p&gt;

&lt;p&gt;import { Test, TestingModule } from '@nestjs/testing';&lt;/p&gt;

&lt;p&gt;import { NotFoundException, BadRequestException } from '@nestjs/common';&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;&lt;br&gt;
markdown&lt;/p&gt;


&lt;h3&gt;
  
  
  3.3 React Rule
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;File: &lt;code&gt;.cursor/rules/unit-test-react.mdc&lt;/code&gt;&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight markdown"&gt;&lt;code&gt;&lt;span class="p"&gt;

---

&lt;/span&gt;
description: React unit test rules&lt;span class="sb"&gt;


&lt;/span&gt;globs: ["src/&lt;span class="gs"&gt;**/*.tsx", "src/**&lt;/span&gt;/&lt;span class="ge"&gt;*.component.tsx", "src/hooks/**/*&lt;/span&gt;.ts"]&lt;span class="sb"&gt;


&lt;/span&gt;&lt;span class="p"&gt;---




&lt;/span&gt;
&lt;span class="gh"&gt;# React Unit Test Rules&lt;/span&gt;&lt;span class="sb"&gt;





&lt;/span&gt;&lt;span class="gu"&gt;## Library: Vitest + @testing-library/react + @testing-library/user-event&lt;/span&gt;&lt;span class="sb"&gt;





&lt;/span&gt;&lt;span class="gu"&gt;## Required setup in vitest.config.ts&lt;/span&gt;&lt;span class="sb"&gt;


&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;&lt;br&gt;
typescript&lt;/p&gt;

&lt;p&gt;export default defineConfig({&lt;/p&gt;

&lt;p&gt;test: {&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;environment: 'jsdom',


globals: true,


setupFiles: ['./src/test/setup.ts']
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;p&gt;}&lt;/p&gt;

&lt;p&gt;})&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;




## setup.ts


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;&lt;br&gt;
typescript&lt;/p&gt;

&lt;p&gt;import '@testing-library/jest-dom';&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;




## Component test structure


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;&lt;br&gt;
typescript&lt;/p&gt;

&lt;p&gt;import { render, screen } from '@testing-library/react';&lt;/p&gt;

&lt;p&gt;import userEvent from '@testing-library/user-event';&lt;/p&gt;

&lt;p&gt;import { vi } from 'vitest';&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;




## Mocking rules for React


- Mock ALL hooks that call APIs: `vi.mock('../hooks/useUsers')`


- Mock ALL context providers — wrap with test-specific providers


- Mock router: use `MemoryRouter` from react-router-dom


- NEVER mock internal state (useState) — test behavior, not implementation





## Query priority (RTL best practice — mandatory)


1. getByRole — prefer always


2. getByLabelText — for forms


3. getByText — for content


4. getByTestId — LAST RESORT only, requires data-testid attribute





## User event — always use userEvent, never fireEvent


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;&lt;br&gt;
typescript&lt;/p&gt;

&lt;p&gt;const user = userEvent.setup();&lt;/p&gt;

&lt;p&gt;await user.click(button);&lt;/p&gt;

&lt;p&gt;await user.type(input, 'value');&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;




## Custom hook testing


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;&lt;br&gt;
typescript&lt;/p&gt;

&lt;p&gt;import { renderHook, act } from '@testing-library/react';&lt;/p&gt;

&lt;p&gt;const { result } = renderHook(() =&amp;gt; useMyHook());&lt;/p&gt;

&lt;p&gt;act(() =&amp;gt; result.current.doSomething());&lt;/p&gt;

&lt;p&gt;expect(result.current.value).toBe('expected');&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;&lt;br&gt;
typescript&lt;/p&gt;


&lt;h3&gt;
  
  
  3.4 Python Rule
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;File: &lt;code&gt;.cursor/rules/unit-test-python.mdc&lt;/code&gt;&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight markdown"&gt;&lt;code&gt;&lt;span class="p"&gt;

---

&lt;/span&gt;
description: Python unit test rules&lt;span class="sb"&gt;


&lt;/span&gt;globs: ["&lt;span class="gs"&gt;**/*.py", "!**&lt;/span&gt;/&lt;span class="ge"&gt;*migrations*&lt;/span&gt;"]&lt;span class="sb"&gt;


&lt;/span&gt;&lt;span class="p"&gt;---




&lt;/span&gt;
&lt;span class="gh"&gt;# Python Unit Test Rules&lt;/span&gt;&lt;span class="sb"&gt;





&lt;/span&gt;&lt;span class="gu"&gt;## Library: pytest + pytest-mock + factory-boy&lt;/span&gt;&lt;span class="sb"&gt;





&lt;/span&gt;&lt;span class="gu"&gt;## File naming&lt;/span&gt;&lt;span class="sb"&gt;


&lt;/span&gt;&lt;span class="p"&gt;-&lt;/span&gt; Source: &lt;span class="sb"&gt;`app/services/user_service.py`


&lt;/span&gt;&lt;span class="p"&gt;-&lt;/span&gt; Test:   &lt;span class="sb"&gt;`tests/unit/test_user_service.py`


&lt;/span&gt;&lt;span class="p"&gt;-&lt;/span&gt; ALWAYS mirror the source directory structure under tests/unit/&lt;span class="sb"&gt;





&lt;/span&gt;&lt;span class="gu"&gt;## Class under test — always use dependency injection&lt;/span&gt;&lt;span class="sb"&gt;


&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;&lt;br&gt;
python&lt;/p&gt;
&lt;h1&gt;
  
  
  GOOD — injectable dependency
&lt;/h1&gt;

&lt;p&gt;class UserService:&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;def __init__(self, repo: UserRepository):


    self.repo = repo
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;h1&gt;
  
  
  BAD — untestable
&lt;/h1&gt;

&lt;p&gt;class UserService:&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;def __init__(self):


    self.repo = UserRepository()  # can't mock this
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;




## Mock pattern — pytest-mock (mocker fixture)


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;p&gt;&lt;br&gt;
python&lt;/p&gt;

&lt;p&gt;def test_raises_when_user_not_found(mocker):&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;mock_repo = mocker.Mock()


mock_repo.find_by_id.return_value = None


service = UserService(mock_repo)


with pytest.raises(UserNotFoundException):


    service.get_user("missing-id")
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;




## Async tests — pytest-asyncio


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;p&gt;&lt;br&gt;
python&lt;/p&gt;

&lt;p&gt;import pytest&lt;/p&gt;

&lt;p&gt;@pytest.mark.asyncio&lt;/p&gt;

&lt;p&gt;async def test_async_service(mocker):&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;mock_repo = mocker.AsyncMock()


...
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;




## Fixture pattern — for shared setup


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;p&gt;&lt;br&gt;
python&lt;/p&gt;

&lt;p&gt;@pytest.fixture&lt;/p&gt;

&lt;p&gt;def user_service(mocker):&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;repo = mocker.Mock()


return UserService(repo), repo
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;p&gt;def test_get_user_happy_path(user_service):&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;service, repo = user_service


repo.find_by_id.return_value = User(id="1", email="a@b.com")


result = service.get_user("1")


assert result.email == "a@b.com"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;




## Naming


- File: `test_[module_name].py`


- Function: `test_[expected_behavior]_when_[condition]`


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;p&gt;&lt;br&gt;
markdown&lt;/p&gt;


&lt;h3&gt;
  
  
  3.5 Angular Rule
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;File: &lt;code&gt;.cursor/rules/unit-test-angular.mdc&lt;/code&gt;&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight markdown"&gt;&lt;code&gt;&lt;span class="p"&gt;

---

&lt;/span&gt;
description: Angular unit test rules&lt;span class="sb"&gt;


&lt;/span&gt;globs: ["src/app/&lt;span class="gs"&gt;**/*.component.ts", "src/app/**&lt;/span&gt;/&lt;span class="ge"&gt;*.service.ts", "src/app/**/*&lt;/span&gt;.pipe.ts", "src/app/&lt;span class="ge"&gt;**&lt;/span&gt;/&lt;span class="err"&gt;*&lt;/span&gt;.guard.ts"]&lt;span class="sb"&gt;


&lt;/span&gt;&lt;span class="p"&gt;---




&lt;/span&gt;
&lt;span class="gh"&gt;# Angular Unit Test Rules&lt;/span&gt;&lt;span class="sb"&gt;





&lt;/span&gt;&lt;span class="gu"&gt;## Library: Jest (NOT Karma — Karma is deprecated Angular 17+)&lt;/span&gt;&lt;span class="sb"&gt;





&lt;/span&gt;&lt;span class="gu"&gt;## Migration from Karma to Jest (one-time)&lt;/span&gt;&lt;span class="sb"&gt;


&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;&lt;br&gt;
bash&lt;/p&gt;

&lt;p&gt;ng add @angular-builders/jest&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;




## TestBed configuration — always minimal


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;&lt;br&gt;
typescript&lt;/p&gt;

&lt;p&gt;await TestBed.configureTestingModule({&lt;/p&gt;

&lt;p&gt;imports: [ComponentUnderTest],  // standalone components&lt;/p&gt;

&lt;p&gt;providers: [&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{ provide: UserService, useValue: mockUserService }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;p&gt;]&lt;/p&gt;

&lt;p&gt;}).compileComponents();&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;




## Service mock pattern


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;&lt;br&gt;
typescript&lt;/p&gt;

&lt;p&gt;const mockUserService = {&lt;/p&gt;

&lt;p&gt;getUser: jest.fn(),&lt;/p&gt;

&lt;p&gt;createUser: jest.fn(),&lt;/p&gt;

&lt;p&gt;};&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;




## Component test — check DOM behavior, not internal state


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;&lt;br&gt;
typescript&lt;/p&gt;

&lt;p&gt;fixture.detectChanges(); // trigger ngOnInit&lt;/p&gt;

&lt;p&gt;const button = fixture.debugElement.query(By.css('[data-testid="submit"]'));&lt;/p&gt;

&lt;p&gt;button.nativeElement.click();&lt;/p&gt;

&lt;p&gt;fixture.detectChanges();&lt;/p&gt;

&lt;p&gt;expect(fixture.debugElement.query(By.css('.error-msg'))).toBeTruthy();&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;




## Pipe test — pure function, no TestBed needed


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;&lt;br&gt;
typescript&lt;/p&gt;

&lt;p&gt;it('should transform date correctly', () =&amp;gt; {&lt;/p&gt;

&lt;p&gt;const pipe = new DateFormatPipe();&lt;/p&gt;

&lt;p&gt;expect(pipe.transform(new Date('2024-01-01'))).toBe('Jan 1, 2024');&lt;/p&gt;

&lt;p&gt;});&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;




## Guard/resolver test — inject and call directly


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;&lt;br&gt;
typescript&lt;/p&gt;

&lt;p&gt;const guard = TestBed.inject(AuthGuard);&lt;/p&gt;

&lt;p&gt;const result = await guard.canActivate(mockRoute, mockState);&lt;/p&gt;

&lt;p&gt;expect(result).toBe(false);&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;&lt;br&gt;
python&lt;/p&gt;


&lt;h3&gt;
  
  
  3.6 Laravel Rule
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;File: &lt;code&gt;.cursor/rules/unit-test-laravel.mdc&lt;/code&gt;&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight markdown"&gt;&lt;code&gt;&lt;span class="p"&gt;

---

&lt;/span&gt;
description: Laravel unit test rules&lt;span class="sb"&gt;


&lt;/span&gt;globs: ["app/Services/&lt;span class="gs"&gt;**/*.php", "app/Models/**&lt;/span&gt;/&lt;span class="ge"&gt;*.php", "app/Http/Requests/**/*&lt;/span&gt;.php", "app/Actions/&lt;span class="ge"&gt;**&lt;/span&gt;/&lt;span class="err"&gt;*&lt;/span&gt;.php"]&lt;span class="sb"&gt;


&lt;/span&gt;&lt;span class="p"&gt;---




&lt;/span&gt;
&lt;span class="gh"&gt;# Laravel Unit Test Rules&lt;/span&gt;&lt;span class="sb"&gt;





&lt;/span&gt;&lt;span class="gu"&gt;## Library: Pest (NOT PHPUnit directly — Pest wraps it with better syntax)&lt;/span&gt;&lt;span class="sb"&gt;





&lt;/span&gt;&lt;span class="gu"&gt;## File location&lt;/span&gt;&lt;span class="sb"&gt;


&lt;/span&gt;&lt;span class="p"&gt;-&lt;/span&gt; Source: &lt;span class="sb"&gt;`app/Services/UserService.php`


&lt;/span&gt;&lt;span class="p"&gt;-&lt;/span&gt; Test:   &lt;span class="sb"&gt;`tests/Unit/Services/UserServiceTest.php`





&lt;/span&gt;&lt;span class="gu"&gt;## Class under test — use constructor injection&lt;/span&gt;&lt;span class="sb"&gt;


&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;&lt;br&gt;
php&lt;/p&gt;

&lt;p&gt;class UserService {&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;public function __construct(


    private readonly UserRepositoryInterface $repo


) {}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;p&gt;}&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;




## Mock pattern — Mockery (included with Pest/PHPUnit)


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;&lt;br&gt;
php&lt;/p&gt;

&lt;p&gt;it('throws exception when user not found', function () {&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// Arrange


$repo = Mockery::mock(UserRepositoryInterface::class);


$repo-&amp;gt;shouldReceive('findById')-&amp;gt;once()-&amp;gt;andReturn(null);


$service = new UserService($repo);





// Act &amp;amp; Assert


expect(fn () =&amp;gt; $service-&amp;gt;getUser('abc'))


    -&amp;gt;toThrow(UserNotFoundException::class);
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;p&gt;});&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;




## Data provider pattern (Pest datasets)


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;&lt;br&gt;
php&lt;/p&gt;

&lt;p&gt;it('validates email format', function (string $email, bool $valid) {&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;expect(validateEmail($email))-&amp;gt;toBe($valid);
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;p&gt;})-&amp;gt;with([&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;['valid@email.com', true],


['notanemail', false],


['', false],


['@nodomain.com', false],
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;p&gt;]);&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;




## What NOT to do in unit tests


- Never call $this-&amp;gt;get() or $this-&amp;gt;post() — that is feature testing


- Never use RefreshDatabase — that is feature/integration testing


- Never resolve from service container — inject directly


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;&lt;br&gt;
markdown&lt;/p&gt;


&lt;h2&gt;
  
  
  Part 4 — CLAUDE.md (Claude Project Memory)
&lt;/h2&gt;

&lt;p&gt;Place this at project root. Claude reads it on every session automatically.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;File: &lt;code&gt;CLAUDE.md&lt;/code&gt;&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight markdown"&gt;&lt;code&gt;

&lt;span class="gh"&gt;# Project: [Your Project Name]&lt;/span&gt;&lt;span class="sb"&gt;


&lt;/span&gt;&lt;span class="gh"&gt;# Claude Unit Test Instructions&lt;/span&gt;&lt;span class="sb"&gt;





&lt;/span&gt;&lt;span class="gu"&gt;## Stack&lt;/span&gt;&lt;span class="sb"&gt;


&lt;/span&gt;&lt;span class="p"&gt;-&lt;/span&gt; Backend: NestJS + TypeScript&lt;span class="sb"&gt;


&lt;/span&gt;&lt;span class="p"&gt;-&lt;/span&gt; Frontend: React + Vite + TypeScript&lt;span class="sb"&gt;


&lt;/span&gt;&lt;span class="p"&gt;-&lt;/span&gt; Testing: Jest (NestJS) + Vitest (React) + Pest (Laravel) + pytest (Python)&lt;span class="sb"&gt;





&lt;/span&gt;&lt;span class="gu"&gt;## Unit Test Rules — NON-NEGOTIABLE&lt;/span&gt;&lt;span class="sb"&gt;





&lt;/span&gt;&lt;span class="gu"&gt;### When asked to generate a unit test:&lt;/span&gt;&lt;span class="sb"&gt;


&lt;/span&gt;&lt;span class="p"&gt;1.&lt;/span&gt; NEVER generate integration or E2E tests unless explicitly asked&lt;span class="sb"&gt;


&lt;/span&gt;&lt;span class="p"&gt;2.&lt;/span&gt; ALWAYS mock every external dependency&lt;span class="sb"&gt;


&lt;/span&gt;&lt;span class="p"&gt;3.&lt;/span&gt; ALWAYS follow AAA (Arrange-Act-Assert) with comments&lt;span class="sb"&gt;


&lt;/span&gt;&lt;span class="p"&gt;4.&lt;/span&gt; ALWAYS generate minimum 4 cases: happy path, null/empty, error thrown, edge case&lt;span class="sb"&gt;


&lt;/span&gt;&lt;span class="p"&gt;5.&lt;/span&gt; NEVER use &lt;span class="sb"&gt;`any`&lt;/span&gt; type in TypeScript tests&lt;span class="sb"&gt;


&lt;/span&gt;&lt;span class="p"&gt;6.&lt;/span&gt; NEVER leave &lt;span class="sb"&gt;`TODO`&lt;/span&gt; comments in generated tests&lt;span class="sb"&gt;





&lt;/span&gt;&lt;span class="gu"&gt;### Naming&lt;/span&gt;&lt;span class="sb"&gt;


&lt;/span&gt;&lt;span class="p"&gt;-&lt;/span&gt; NestJS: &lt;span class="sb"&gt;`[name].service.spec.ts`&lt;/span&gt; inside same directory as source&lt;span class="sb"&gt;


&lt;/span&gt;&lt;span class="p"&gt;-&lt;/span&gt; React: &lt;span class="sb"&gt;`[ComponentName].test.tsx`&lt;/span&gt; inside &lt;span class="sb"&gt;`__tests__/`&lt;/span&gt; or same directory&lt;span class="sb"&gt;


&lt;/span&gt;&lt;span class="p"&gt;-&lt;/span&gt; Python: &lt;span class="sb"&gt;`test_[module].py`&lt;/span&gt; under &lt;span class="sb"&gt;`tests/unit/`


&lt;/span&gt;&lt;span class="p"&gt;-&lt;/span&gt; Laravel: &lt;span class="sb"&gt;`[Name]Test.php`&lt;/span&gt; under &lt;span class="sb"&gt;`tests/Unit/`





&lt;/span&gt;&lt;span class="gu"&gt;### Test should describe BEHAVIOR, not implementation&lt;/span&gt;&lt;span class="sb"&gt;


&lt;/span&gt;GOOD: "should return empty array when no users match search"&lt;span class="sb"&gt;


&lt;/span&gt;BAD: "test getUserByFilter"&lt;span class="sb"&gt;





&lt;/span&gt;&lt;span class="gu"&gt;### If you are unsure of the correct mock structure:&lt;/span&gt;&lt;span class="sb"&gt;


&lt;/span&gt;&lt;span class="p"&gt;-&lt;/span&gt; Ask what the dependency interface looks like&lt;span class="sb"&gt;


&lt;/span&gt;&lt;span class="p"&gt;-&lt;/span&gt; Do NOT invent method names that don't exist in the source&lt;span class="sb"&gt;





&lt;/span&gt;&lt;span class="gu"&gt;### Coverage target: 80% lines, 75% branches per module&lt;/span&gt;&lt;span class="sb"&gt;





&lt;/span&gt;&lt;span class="gu"&gt;## Project Structure Reference&lt;/span&gt;&lt;span class="sb"&gt;


&lt;/span&gt;src/&lt;span class="sb"&gt;


&lt;/span&gt;  modules/&lt;span class="sb"&gt;


    users/


      users.service.ts


      users.service.spec.ts   ← unit test lives here


      users.repository.ts


      users.repository.spec.ts


&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Part 5 — MCP Servers for Unit Testing in Cursor + Claude
&lt;/h2&gt;

&lt;p&gt;MCP (Model Context Protocol) servers extend AI capabilities. For unit testing, these are the relevant ones:&lt;/p&gt;

&lt;h3&gt;
  
  
  5.1 Filesystem MCP (Built-in Cursor — use directly)
&lt;/h3&gt;

&lt;p&gt;Cursor already has filesystem access. No extra MCP needed to read source files and generate tests. The &lt;code&gt;.cursor/rules/&lt;/code&gt; system handles this.&lt;/p&gt;

&lt;h3&gt;
  
  
  5.2 Available MCP Servers for Testing Workflows
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;1. &lt;code&gt;@executeautomation/playwright-mcp-server&lt;/code&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Scope: E2E only — not relevant for unit tests&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Skip for this use case&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;2. &lt;code&gt;@modelcontextprotocol/server-filesystem&lt;/code&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Gives Claude access to project files&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Use in Claude Desktop to read source → generate tests&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Install: configured in &lt;code&gt;claude_desktop_config.json&lt;/code&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;3. Custom Testing MCP (Build This — Highest Value)&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Build a lightweight MCP server that:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Reads a source file&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Extracts function signatures + types&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Returns structured JSON to Claude&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Claude generates tests from structure, not guesswork&lt;br&gt;
&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;

&lt;span class="c1"&gt;// mcp-test-generator/src/index.ts&lt;/span&gt;


&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;Server&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@modelcontextprotocol/sdk/server/index.js&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;


&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;StdioServerTransport&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@modelcontextprotocol/sdk/server/stdio.js&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;


&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nx"&gt;ts&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;typescript&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;





&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;server&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Server&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;test-generator&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;version&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;1.0.0&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;


  &lt;span class="na"&gt;capabilities&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;tools&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;


&lt;span class="p"&gt;});&lt;/span&gt;





&lt;span class="nx"&gt;server&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setRequestHandler&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;tools/call&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;


  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;params&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;extract_signatures&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;


    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;filePath&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;params&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;arguments&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;


    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;signatures&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;extractFunctionSignatures&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;filePath&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// parse AST&lt;/span&gt;


    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;content&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[{&lt;/span&gt; &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;text&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;text&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;stringify&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;signatures&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;}]&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;


  &lt;span class="p"&gt;}&lt;/span&gt;


&lt;span class="p"&gt;});&lt;/span&gt;





&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;extractFunctionSignatures&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;filePath&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;


  &lt;span class="c1"&gt;// Use TypeScript compiler API to extract:&lt;/span&gt;


  &lt;span class="c1"&gt;// - class name&lt;/span&gt;


  &lt;span class="c1"&gt;// - method names&lt;/span&gt;


  &lt;span class="c1"&gt;// - parameter types&lt;/span&gt;


  &lt;span class="c1"&gt;// - return types&lt;/span&gt;


  &lt;span class="c1"&gt;// - injected dependencies (constructor params)&lt;/span&gt;


  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;program&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;ts&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;createProgram&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="nx"&gt;filePath&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="p"&gt;{});&lt;/span&gt;


  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;sourceFile&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;program&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getSourceFile&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;filePath&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;


  &lt;span class="c1"&gt;// ... AST traversal&lt;/span&gt;


  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;className&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;methods&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;dependencies&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;


&lt;span class="p"&gt;}&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Why this matters:&lt;/strong&gt; When Claude receives typed signatures instead of raw source code, it cannot hallucinate — it generates tests from concrete types, not guesses.&lt;/p&gt;

&lt;h3&gt;
  
  
  5.3 Claude Desktop MCP Config
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="err"&gt;//&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;~/Library/Application&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;Support/Claude/claude_desktop_config.json&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;(macOS)&lt;/span&gt;&lt;span class="w"&gt;


&lt;/span&gt;&lt;span class="err"&gt;//&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;%APPDATA%\Claude\claude_desktop_config.json&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;(Windows)&lt;/span&gt;&lt;span class="w"&gt;


&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;


  &lt;/span&gt;&lt;span class="nl"&gt;"mcpServers"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;


    &lt;/span&gt;&lt;span class="nl"&gt;"filesystem"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;


      &lt;/span&gt;&lt;span class="nl"&gt;"command"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"npx"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;


      &lt;/span&gt;&lt;span class="nl"&gt;"args"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"-y"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"@modelcontextprotocol/server-filesystem"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"/path/to/your/project"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;


    &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;


    &lt;/span&gt;&lt;span class="nl"&gt;"test-generator"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;


      &lt;/span&gt;&lt;span class="nl"&gt;"command"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"node"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;


      &lt;/span&gt;&lt;span class="nl"&gt;"args"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"/path/to/your/mcp-test-generator/dist/index.js"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;


    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;


  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;


&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;


&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  5.4 Cursor MCP Config
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="err"&gt;//&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;.cursor/mcp.json&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;(project-level)&lt;/span&gt;&lt;span class="w"&gt;


&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;


  &lt;/span&gt;&lt;span class="nl"&gt;"mcpServers"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;


    &lt;/span&gt;&lt;span class="nl"&gt;"test-generator"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;


      &lt;/span&gt;&lt;span class="nl"&gt;"command"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"node"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;


      &lt;/span&gt;&lt;span class="nl"&gt;"args"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"./tools/mcp-test-generator/dist/index.js"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;


    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;


  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;


&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;


&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Part 6 — Anti-Hallucination Prompt Templates
&lt;/h2&gt;

&lt;p&gt;The root cause of AI hallucination in tests: AI invents method names, wrong mock structures, non-existent imports. These prompts eliminate that.&lt;/p&gt;

&lt;h3&gt;
  
  
  6.1 Cursor Cmd+K Prompt (Use This Exactly)
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;

Generate a unit &lt;span class="nb"&gt;test &lt;/span&gt;file &lt;span class="k"&gt;for &lt;/span&gt;this &lt;span class="o"&gt;[&lt;/span&gt;NestJS service / React component / Python class / Angular service / Laravel service].





Rules:


- Library: &lt;span class="o"&gt;[&lt;/span&gt;Jest / Vitest / pytest / Jest / Pest]


- Test only THIS file — no integration


- Mock ALL dependencies listed &lt;span class="k"&gt;in &lt;/span&gt;the constructor/props


- Follow AAA pattern with comments


- Minimum 4 &lt;span class="nb"&gt;test &lt;/span&gt;cases per public method


- Use ONLY methods/properties that exist &lt;span class="k"&gt;in &lt;/span&gt;this &lt;span class="nb"&gt;source &lt;/span&gt;file


- Do NOT import anything not shown &lt;span class="k"&gt;in &lt;/span&gt;the &lt;span class="nb"&gt;source&lt;/span&gt;


- Naming: &lt;span class="s2"&gt;"should [behavior] when [condition]"&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  6.2 Claude Prompt (For CLAUDE.md aware sessions)
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight markdown"&gt;&lt;code&gt;

Read [filename].&lt;span class="sb"&gt;


&lt;/span&gt;Extract:&lt;span class="sb"&gt;


&lt;/span&gt;&lt;span class="p"&gt;1.&lt;/span&gt; Class/function name&lt;span class="sb"&gt;


&lt;/span&gt;&lt;span class="p"&gt;2.&lt;/span&gt; All public methods with parameter types and return types&lt;span class="sb"&gt;


&lt;/span&gt;&lt;span class="p"&gt;3.&lt;/span&gt; All constructor dependencies (for mocking)&lt;span class="sb"&gt;





&lt;/span&gt;Then generate the unit test file following CLAUDE.md rules.&lt;span class="sb"&gt;


&lt;/span&gt;Do NOT assume any method exists unless you can see it in the source.&lt;span class="sb"&gt;


&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  6.3 Batch Test Generation Prompt
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;

&lt;span class="k"&gt;For&lt;/span&gt; &lt;span class="n"&gt;each&lt;/span&gt; &lt;span class="n"&gt;file&lt;/span&gt; &lt;span class="n"&gt;in&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;directory&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="n"&gt;generate&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="n"&gt;corresponding&lt;/span&gt; &lt;span class="mf"&gt;.&lt;/span&gt;&lt;span class="n"&gt;spec&lt;/span&gt;&lt;span class="mf"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ts&lt;/span&gt; &lt;span class="n"&gt;file&lt;/span&gt;&lt;span class="mf"&gt;.&lt;/span&gt;


&lt;span class="nc"&gt;Process&lt;/span&gt; &lt;span class="n"&gt;one&lt;/span&gt; &lt;span class="n"&gt;file&lt;/span&gt; &lt;span class="n"&gt;at&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="mf"&gt;.&lt;/span&gt;


&lt;span class="k"&gt;For&lt;/span&gt; &lt;span class="n"&gt;each&lt;/span&gt; &lt;span class="n"&gt;file&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;


  &lt;span class="mf"&gt;1.&lt;/span&gt; &lt;span class="nc"&gt;Read&lt;/span&gt; &lt;span class="n"&gt;the&lt;/span&gt; &lt;span class="n"&gt;source&lt;/span&gt;


  &lt;span class="mf"&gt;2.&lt;/span&gt; &lt;span class="k"&gt;List&lt;/span&gt; &lt;span class="n"&gt;the&lt;/span&gt; &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;methods&lt;/span&gt; &lt;span class="n"&gt;you&lt;/span&gt; &lt;span class="nf"&gt;found&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;confirm&lt;/span&gt; &lt;span class="n"&gt;before&lt;/span&gt; &lt;span class="n"&gt;generating&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;


  &lt;span class="mf"&gt;3.&lt;/span&gt; &lt;span class="nc"&gt;Generate&lt;/span&gt; &lt;span class="n"&gt;the&lt;/span&gt; &lt;span class="n"&gt;test&lt;/span&gt; &lt;span class="n"&gt;file&lt;/span&gt;


  &lt;span class="mf"&gt;4.&lt;/span&gt; &lt;span class="nc"&gt;Show&lt;/span&gt; &lt;span class="n"&gt;the&lt;/span&gt; &lt;span class="n"&gt;test&lt;/span&gt; &lt;span class="n"&gt;file&lt;/span&gt; &lt;span class="n"&gt;path&lt;/span&gt;





&lt;span class="k"&gt;Do&lt;/span&gt; &lt;span class="n"&gt;not&lt;/span&gt; &lt;span class="n"&gt;proceed&lt;/span&gt; &lt;span class="n"&gt;to&lt;/span&gt; &lt;span class="n"&gt;the&lt;/span&gt; &lt;span class="n"&gt;next&lt;/span&gt; &lt;span class="n"&gt;file&lt;/span&gt; &lt;span class="n"&gt;until&lt;/span&gt; &lt;span class="n"&gt;the&lt;/span&gt; &lt;span class="n"&gt;current&lt;/span&gt; &lt;span class="n"&gt;one&lt;/span&gt; &lt;span class="n"&gt;is&lt;/span&gt; &lt;span class="n"&gt;confirmed&lt;/span&gt;&lt;span class="mf"&gt;.&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Part 7 — Project Structure Convention
&lt;/h2&gt;

&lt;p&gt;All stacks follow the same proximity principle: &lt;strong&gt;test file lives next to source file&lt;/strong&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Node.js / NestJS / Angular
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight markdown"&gt;&lt;code&gt;

src/&lt;span class="sb"&gt;


&lt;/span&gt;  modules/&lt;span class="sb"&gt;


    users/


      users.service.ts


      users.service.spec.ts        ← unit test


      users.repository.ts


      users.repository.spec.ts     ← unit test


      users.guard.ts


      users.guard.spec.ts          ← unit test


&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  React
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

src/


  components/


    UserCard/


      UserCard.tsx


      UserCard.test.tsx            ← unit test


      UserCard.stories.tsx         ← storybook (optional)


  hooks/


    useUserData.ts


    useUserData.test.ts            ← unit test


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Python
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

app/


  services/


    user_service.py


tests/


  unit/


    services/


      test_user_service.py        ← mirrors app/ structure


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Laravel
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

app/


  Services/


    UserService.php


tests/


  Unit/


    Services/


      UserServiceTest.php         ← mirrors app/ structure


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Part 8 — CI Enforcement
&lt;/h2&gt;

&lt;p&gt;All of this means nothing without enforcement. The pipeline is the final gate.&lt;/p&gt;

&lt;h3&gt;
  
  
  GitHub Actions — Multi-stack parallel
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;

&lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Unit Tests&lt;/span&gt;





&lt;span class="na"&gt;on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;push&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;pull_request&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;





&lt;span class="na"&gt;jobs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;


  &lt;span class="na"&gt;nestjs-unit&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;


    &lt;span class="na"&gt;runs-on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;ubuntu-latest&lt;/span&gt;


    &lt;span class="na"&gt;steps&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;


      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;actions/checkout@v4&lt;/span&gt;


      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;actions/setup-node@v4&lt;/span&gt;


        &lt;span class="na"&gt;with&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;{&lt;/span&gt; &lt;span class="nv"&gt;node-version&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;20'&lt;/span&gt; &lt;span class="pi"&gt;}&lt;/span&gt;


      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;npm ci&lt;/span&gt;


      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;npm run test:unit -- --coverage --coverageThreshold='{"global":{"lines":80}}'&lt;/span&gt;





  &lt;span class="na"&gt;react-unit&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;


    &lt;span class="na"&gt;runs-on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;ubuntu-latest&lt;/span&gt;


    &lt;span class="na"&gt;steps&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;


      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;actions/checkout@v4&lt;/span&gt;


      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;actions/setup-node@v4&lt;/span&gt;


        &lt;span class="na"&gt;with&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;{&lt;/span&gt; &lt;span class="nv"&gt;node-version&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;20'&lt;/span&gt; &lt;span class="pi"&gt;}&lt;/span&gt;


      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;npm ci&lt;/span&gt;


      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;npx vitest run --coverage&lt;/span&gt;





  &lt;span class="na"&gt;python-unit&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;


    &lt;span class="na"&gt;runs-on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;ubuntu-latest&lt;/span&gt;


    &lt;span class="na"&gt;steps&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;


      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;actions/checkout@v4&lt;/span&gt;


      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;actions/setup-python@v5&lt;/span&gt;


        &lt;span class="na"&gt;with&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;{&lt;/span&gt; &lt;span class="nv"&gt;python-version&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;3.12'&lt;/span&gt; &lt;span class="pi"&gt;}&lt;/span&gt;


      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;pip install -r requirements-dev.txt&lt;/span&gt;


      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;pytest tests/unit/ --cov=app --cov-fail-under=80&lt;/span&gt;





  &lt;span class="na"&gt;laravel-unit&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;


    &lt;span class="na"&gt;runs-on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;ubuntu-latest&lt;/span&gt;


    &lt;span class="na"&gt;steps&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;


      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;actions/checkout@v4&lt;/span&gt;


      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;shivammathur/setup-php@v2&lt;/span&gt;


        &lt;span class="na"&gt;with&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;{&lt;/span&gt; &lt;span class="nv"&gt;php-version&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;8.3'&lt;/span&gt; &lt;span class="pi"&gt;}&lt;/span&gt;


      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;composer install&lt;/span&gt;


      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;./vendor/bin/pest --coverage --min=80&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Pre-commit Hook (Husky — Node stacks)
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="err"&gt;//&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;package.json&lt;/span&gt;&lt;span class="w"&gt;


&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;


  &lt;/span&gt;&lt;span class="nl"&gt;"lint-staged"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;


    &lt;/span&gt;&lt;span class="nl"&gt;"src/**/*.service.ts"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"jest --findRelatedTests --passWithNoTests"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;


    &lt;/span&gt;&lt;span class="nl"&gt;"src/**/*.tsx"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"vitest related --run"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;


  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;


&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;


&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Part 9 — Quick Start Checklist
&lt;/h2&gt;

&lt;h3&gt;
  
  
  New Project
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

□ Install test library (one per stack — see Part 1)


□ Configure jest.config.ts / vitest.config.ts / pytest.ini / pest.php


□ Create .cursor/rules/ directory with all rule files from Part 3


□ Create CLAUDE.md at project root from Part 4


□ Add coverage thresholds to config


□ Add pre-commit hooks (Husky for Node, pre-commit for Python)


□ Add CI workflow from Part 8


□ Create test factory files (one per major entity)


□ Write first failing test → implement → green → commit


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Existing Project
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

□ Add test library without touching existing code


□ Add .cursor/rules/ + CLAUDE.md


□ Run coverage on existing code → document current baseline


□ Pick 3 critical services → generate tests → set as new baseline


□ Add CI with threshold = current baseline (not ideal — current)


□ Raise threshold by 5% per sprint


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Appendix — Install Commands Per Stack
&lt;/h2&gt;

&lt;h3&gt;
  
  
  NestJS
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;

npm &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;--save-dev&lt;/span&gt; jest ts-jest @types/jest @nestjs/testing jest-mock-extended @golevelup/ts-jest


npx ts-jest config:init


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  React (Vite)
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;

npm &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;--save-dev&lt;/span&gt; vitest @vitest/coverage-v8 @testing-library/react @testing-library/user-event @testing-library/jest-dom jsdom


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Python
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;

pip &lt;span class="nb"&gt;install &lt;/span&gt;pytest pytest-cov pytest-mock pytest-asyncio factory-boy


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Angular
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;

ng add @angular-builders/jest


npm &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;--save-dev&lt;/span&gt; jest jest-preset-angular @types/jest


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Laravel
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;

composer require pestphp/pest pestphp/pest-plugin-laravel &lt;span class="nt"&gt;--dev&lt;/span&gt;


./vendor/bin/pest &lt;span class="nt"&gt;--init&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;p&gt;&lt;em&gt;Last updated: 2025 — verify library major versions before adopting&lt;/em&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>javascript</category>
      <category>testing</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>Unit Test AI Guide — Zero Hallucination, Cross-Stack Standard</title>
      <dc:creator>Bhaumik</dc:creator>
      <pubDate>Fri, 19 Jun 2026 12:21:02 +0000</pubDate>
      <link>https://dev.to/bhaumik-viitor/unit-test-ai-guide-zero-hallucination-cross-stack-standard-4g8j</link>
      <guid>https://dev.to/bhaumik-viitor/unit-test-ai-guide-zero-hallucination-cross-stack-standard-4g8j</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Focus:&lt;/strong&gt; Unit Tests ONLY — no integration, no E2E  &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Stacks:&lt;/strong&gt; Node.js (NestJS/Express) · React.js · Python · Angular · Laravel  &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Goal:&lt;/strong&gt; AI generates unit tests consistently, deterministically, without hallucination  &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;IDE:&lt;/strong&gt; Cursor (Primary) + Claude (Secondary)&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  Part 1 — Best Single Library Per Stack (Final Decision)
&lt;/h2&gt;

&lt;p&gt;Do not mix libraries. Pick one per stack, configure it fully, never deviate.&lt;/p&gt;

&lt;p&gt;| Stack | Library | Why This One |&lt;/p&gt;

&lt;p&gt;|---|---|---|&lt;/p&gt;

&lt;p&gt;| &lt;strong&gt;Node.js / NestJS / Express&lt;/strong&gt; | &lt;code&gt;Jest&lt;/code&gt; | Native DI mocking, &lt;code&gt;@nestjs/testing&lt;/code&gt; built around it, widest ecosystem |&lt;/p&gt;

&lt;p&gt;| &lt;strong&gt;React.js&lt;/strong&gt; | &lt;code&gt;Vitest&lt;/code&gt; + &lt;code&gt;@testing-library/react&lt;/code&gt; | Native Vite/ESM support, Jest-compatible API, 3–10x faster |&lt;/p&gt;

&lt;p&gt;| &lt;strong&gt;Python&lt;/strong&gt; | &lt;code&gt;pytest&lt;/code&gt; | De facto standard, fixture system eliminates boilerplate, best plugin ecosystem |&lt;/p&gt;

&lt;p&gt;| &lt;strong&gt;Angular&lt;/strong&gt; | &lt;code&gt;Jest&lt;/code&gt; (replace Karma) | Karma is deprecated in Angular 17+; Jest is the official migration target |&lt;/p&gt;

&lt;p&gt;| &lt;strong&gt;Laravel&lt;/strong&gt; | &lt;code&gt;Pest&lt;/code&gt; | Modern syntax, built on PHPUnit, higher signal-to-noise ratio |&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Rule:&lt;/strong&gt; If someone suggests a second library for the same stack, reject it. One library per stack, configured once, followed always.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  Part 2 — IDE: Cursor (Only Choice for This Goal)
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Why Cursor and Not VS Code / WebStorm
&lt;/h3&gt;

&lt;p&gt;| Capability | Cursor | VS Code + Copilot | WebStorm |&lt;/p&gt;

&lt;p&gt;|---|---|---|---|&lt;/p&gt;

&lt;p&gt;| Project-level AI rules | ✅ &lt;code&gt;.cursor/rules/&lt;/code&gt; | ❌ | ❌ |&lt;/p&gt;

&lt;p&gt;| Codebase-aware context | ✅ &lt;code&gt;@codebase&lt;/code&gt; | Partial | Partial |&lt;/p&gt;

&lt;p&gt;| Run terminal + read output | ✅ Composer | ❌ | ❌ |&lt;/p&gt;

&lt;p&gt;| Multi-file generation | ✅ Agent mode | Limited | ❌ |&lt;/p&gt;

&lt;p&gt;| Custom instructions per filetype | ✅ | ❌ | ❌ |&lt;/p&gt;

&lt;p&gt;| MCP server integration | ✅ | ❌ | ❌ |&lt;/p&gt;

&lt;p&gt;Cursor's &lt;code&gt;.cursor/rules/&lt;/code&gt; system is the &lt;strong&gt;only IDE-native mechanism&lt;/strong&gt; that injects persistent, project-scoped instructions into every AI interaction — this is what prevents hallucination at the source.&lt;/p&gt;

&lt;h3&gt;
  
  
  Cursor Setup for This Project
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
project-root/

├── .cursor/

│   └── rules/

│       ├── unit-test-global.mdc       ← applies to all files

│       ├── unit-test-nestjs.mdc       ← applies to *.service.ts, *.guard.ts

│       ├── unit-test-react.mdc        ← applies to *.tsx, *.component.tsx

│       ├── unit-test-python.mdc       ← applies to *.py

│       ├── unit-test-angular.mdc      ← applies to *.component.ts, *.service.ts

│       └── unit-test-laravel.mdc      ← applies to *Service.php, *Model.php

├── CLAUDE.md                          ← Claude project memory file

└── ...

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Part 3 — Cursor Rules Files (Anti-Hallucination Core)
&lt;/h2&gt;

&lt;p&gt;These files are injected into every AI prompt automatically when working on matching files.&lt;/p&gt;

&lt;h3&gt;
  
  
  3.1 Global Unit Test Rule
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;File: &lt;code&gt;.cursor/rules/unit-test-global.mdc&lt;/code&gt;&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight markdown"&gt;&lt;code&gt;&lt;span class="p"&gt;
---
&lt;/span&gt;
description: Global unit test rules — applies to all files in this project

globs: ["&lt;span class="gs"&gt;**/*.spec.ts", "**&lt;/span&gt;/&lt;span class="ge"&gt;*.test.ts", "**/*&lt;/span&gt;.spec.tsx", "&lt;span class="gs"&gt;**/*_test.py", "**&lt;/span&gt;/Test&lt;span class="err"&gt;*&lt;/span&gt;.php"]

alwaysApply: true
&lt;span class="p"&gt;
---


&lt;/span&gt;
&lt;span class="gh"&gt;# Unit Test Contract — MUST FOLLOW, NO EXCEPTIONS&lt;/span&gt;&lt;span class="sb"&gt;



&lt;/span&gt;&lt;span class="gu"&gt;## What is a unit test here&lt;/span&gt;
&lt;span class="p"&gt;
-&lt;/span&gt; Tests ONE class or function in complete isolation
&lt;span class="p"&gt;
-&lt;/span&gt; ALL external dependencies are mocked — no real DB, no real HTTP, no real file system
&lt;span class="p"&gt;
-&lt;/span&gt; Each test runs independently — no shared mutable state between tests
&lt;span class="p"&gt;
-&lt;/span&gt; Runs in &amp;lt; 100ms&lt;span class="sb"&gt;



&lt;/span&gt;&lt;span class="gu"&gt;## Structure: AAA — Always, Without Exception&lt;/span&gt;

Every test MUST have these three sections, with comments:

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;// Arrange — set up inputs, mocks, expected values&lt;/p&gt;

&lt;p&gt;// Act — call the single function/method under test&lt;/p&gt;

&lt;p&gt;// Assert — verify exactly one outcome&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;


## Naming Convention — Mandatory

- File: `[module-name].spec.ts` or `[module-name].unit.spec.ts`

- Describe block: exact class or function name

- It/test block: "should [expected behavior] when [specific condition]"

  GOOD: "should throw NotFoundException when user does not exist"

  BAD:  "user not found", "test 1", "works correctly"



## What to test per function — minimum coverage

1. Happy path — valid input → expected output

2. Null/undefined input — how does it fail safely

3. Empty input — empty string, empty array, zero

4. Error path — when dependency throws, what happens

5. Boundary — max length, negative numbers, boolean edge



## What NOT to include in unit tests

- Database queries (mock the repository)

- HTTP calls (mock the service/axios/fetch)

- File system operations (mock fs)

- Timer behavior (use jest.useFakeTimers)

- Random values (mock Math.random or faker with fixed seed)



## AI Instruction

When asked to generate a unit test:

1. READ the function signature and types first

2. IDENTIFY all dependencies (constructor args, imported modules)

3. MOCK every dependency — never use real implementations

4. Generate minimum 4 test cases per method (happy, null, error, edge)

5. NEVER import from test doubles or assume what isn't in the source file

6. If you are unsure of a type — ASK, do not assume

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h3&gt;
  
  
  3.2 NestJS Rule
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;File: &lt;code&gt;.cursor/rules/unit-test-nestjs.mdc&lt;/code&gt;&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight markdown"&gt;&lt;code&gt;&lt;span class="p"&gt;
---
&lt;/span&gt;
description: NestJS unit test rules

globs: ["src/&lt;span class="gs"&gt;**/*.service.ts", "src/**&lt;/span&gt;/&lt;span class="ge"&gt;*.guard.ts", "src/**/*&lt;/span&gt;.interceptor.ts", "src/&lt;span class="ge"&gt;**&lt;/span&gt;/&lt;span class="err"&gt;*&lt;/span&gt;.pipe.ts"]
&lt;span class="p"&gt;
---


&lt;/span&gt;
&lt;span class="gh"&gt;# NestJS Unit Test Rules&lt;/span&gt;&lt;span class="sb"&gt;



&lt;/span&gt;&lt;span class="gu"&gt;## Library: Jest + @nestjs/testing + jest-mock-extended&lt;/span&gt;&lt;span class="sb"&gt;



&lt;/span&gt;&lt;span class="gu"&gt;## Always use Test.createTestingModule&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;&lt;br&gt;
typescript&lt;/p&gt;

&lt;p&gt;const module = await Test.createTestingModule({&lt;/p&gt;

&lt;p&gt;providers: [&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;SubjectService,

{ provide: DependencyService, useValue: mockDependency }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;p&gt;]&lt;/p&gt;

&lt;p&gt;}).compile();&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;


## Mock Pattern — jest-mock-extended

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;&lt;br&gt;
typescript&lt;/p&gt;

&lt;p&gt;import { createMock } from '@golevelup/ts-jest';&lt;/p&gt;

&lt;p&gt;// OR&lt;/p&gt;

&lt;p&gt;import { mock } from 'jest-mock-extended';&lt;/p&gt;

&lt;p&gt;const mockUserRepo = mock();&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;


## Never

- Never use `new SubjectService()` directly — always use TestingModule

- Never let `useValue` contain real implementations

- Never test more than one service per describe block



## Repository Mock Template

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;&lt;br&gt;
typescript&lt;/p&gt;

&lt;p&gt;const mockRepo = {&lt;/p&gt;

&lt;p&gt;findOne: jest.fn(),&lt;/p&gt;

&lt;p&gt;save: jest.fn(),&lt;/p&gt;

&lt;p&gt;delete: jest.fn(),&lt;/p&gt;

&lt;p&gt;findAll: jest.fn(),&lt;/p&gt;

&lt;p&gt;update: jest.fn(),&lt;/p&gt;

&lt;p&gt;};&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;


## Required imports for every NestJS spec file

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;&lt;br&gt;
typescript&lt;/p&gt;

&lt;p&gt;import { Test, TestingModule } from '@nestjs/testing';&lt;/p&gt;

&lt;p&gt;import { NotFoundException, BadRequestException } from '@nestjs/common';&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;&lt;br&gt;
markdown&lt;/p&gt;


&lt;h3&gt;
  
  
  3.3 React Rule
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;File: &lt;code&gt;.cursor/rules/unit-test-react.mdc&lt;/code&gt;&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight markdown"&gt;&lt;code&gt;&lt;span class="p"&gt;
---
&lt;/span&gt;
description: React unit test rules

globs: ["src/&lt;span class="gs"&gt;**/*.tsx", "src/**&lt;/span&gt;/&lt;span class="ge"&gt;*.component.tsx", "src/hooks/**/*&lt;/span&gt;.ts"]
&lt;span class="p"&gt;
---


&lt;/span&gt;
&lt;span class="gh"&gt;# React Unit Test Rules&lt;/span&gt;&lt;span class="sb"&gt;



&lt;/span&gt;&lt;span class="gu"&gt;## Library: Vitest + @testing-library/react + @testing-library/user-event&lt;/span&gt;&lt;span class="sb"&gt;



&lt;/span&gt;&lt;span class="gu"&gt;## Required setup in vitest.config.ts&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;&lt;br&gt;
typescript&lt;/p&gt;

&lt;p&gt;export default defineConfig({&lt;/p&gt;

&lt;p&gt;test: {&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;environment: 'jsdom',

globals: true,

setupFiles: ['./src/test/setup.ts']
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;p&gt;}&lt;/p&gt;

&lt;p&gt;})&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;


## setup.ts

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;&lt;br&gt;
typescript&lt;/p&gt;

&lt;p&gt;import '@testing-library/jest-dom';&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;


## Component test structure

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;&lt;br&gt;
typescript&lt;/p&gt;

&lt;p&gt;import { render, screen } from '@testing-library/react';&lt;/p&gt;

&lt;p&gt;import userEvent from '@testing-library/user-event';&lt;/p&gt;

&lt;p&gt;import { vi } from 'vitest';&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;


## Mocking rules for React

- Mock ALL hooks that call APIs: `vi.mock('../hooks/useUsers')`

- Mock ALL context providers — wrap with test-specific providers

- Mock router: use `MemoryRouter` from react-router-dom

- NEVER mock internal state (useState) — test behavior, not implementation



## Query priority (RTL best practice — mandatory)

1. getByRole — prefer always

2. getByLabelText — for forms

3. getByText — for content

4. getByTestId — LAST RESORT only, requires data-testid attribute



## User event — always use userEvent, never fireEvent

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;&lt;br&gt;
typescript&lt;/p&gt;

&lt;p&gt;const user = userEvent.setup();&lt;/p&gt;

&lt;p&gt;await user.click(button);&lt;/p&gt;

&lt;p&gt;await user.type(input, 'value');&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;


## Custom hook testing

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;&lt;br&gt;
typescript&lt;/p&gt;

&lt;p&gt;import { renderHook, act } from '@testing-library/react';&lt;/p&gt;

&lt;p&gt;const { result } = renderHook(() =&amp;gt; useMyHook());&lt;/p&gt;

&lt;p&gt;act(() =&amp;gt; result.current.doSomething());&lt;/p&gt;

&lt;p&gt;expect(result.current.value).toBe('expected');&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;&lt;br&gt;
typescript&lt;/p&gt;


&lt;h3&gt;
  
  
  3.4 Python Rule
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;File: &lt;code&gt;.cursor/rules/unit-test-python.mdc&lt;/code&gt;&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight markdown"&gt;&lt;code&gt;&lt;span class="p"&gt;
---
&lt;/span&gt;
description: Python unit test rules

globs: ["&lt;span class="gs"&gt;**/*.py", "!**&lt;/span&gt;/&lt;span class="ge"&gt;*migrations*&lt;/span&gt;"]
&lt;span class="p"&gt;
---


&lt;/span&gt;
&lt;span class="gh"&gt;# Python Unit Test Rules&lt;/span&gt;&lt;span class="sb"&gt;



&lt;/span&gt;&lt;span class="gu"&gt;## Library: pytest + pytest-mock + factory-boy&lt;/span&gt;&lt;span class="sb"&gt;



&lt;/span&gt;&lt;span class="gu"&gt;## File naming&lt;/span&gt;
&lt;span class="p"&gt;
-&lt;/span&gt; Source: &lt;span class="sb"&gt;`app/services/user_service.py`&lt;/span&gt;
&lt;span class="p"&gt;
-&lt;/span&gt; Test:   &lt;span class="sb"&gt;`tests/unit/test_user_service.py`&lt;/span&gt;
&lt;span class="p"&gt;
-&lt;/span&gt; ALWAYS mirror the source directory structure under tests/unit/&lt;span class="sb"&gt;



&lt;/span&gt;&lt;span class="gu"&gt;## Class under test — always use dependency injection&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;&lt;br&gt;
python&lt;/p&gt;
&lt;h1&gt;
  
  
  GOOD — injectable dependency
&lt;/h1&gt;

&lt;p&gt;class UserService:&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;def __init__(self, repo: UserRepository):

    self.repo = repo
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;h1&gt;
  
  
  BAD — untestable
&lt;/h1&gt;

&lt;p&gt;class UserService:&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;def __init__(self):

    self.repo = UserRepository()  # can't mock this
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;


## Mock pattern — pytest-mock (mocker fixture)

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;p&gt;&lt;br&gt;
python&lt;/p&gt;

&lt;p&gt;def test_raises_when_user_not_found(mocker):&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;mock_repo = mocker.Mock()

mock_repo.find_by_id.return_value = None

service = UserService(mock_repo)

with pytest.raises(UserNotFoundException):

    service.get_user("missing-id")
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;


## Async tests — pytest-asyncio

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;p&gt;&lt;br&gt;
python&lt;/p&gt;

&lt;p&gt;import pytest&lt;/p&gt;

&lt;p&gt;@pytest.mark.asyncio&lt;/p&gt;

&lt;p&gt;async def test_async_service(mocker):&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;mock_repo = mocker.AsyncMock()

...
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;


## Fixture pattern — for shared setup

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;p&gt;&lt;br&gt;
python&lt;/p&gt;

&lt;p&gt;@pytest.fixture&lt;/p&gt;

&lt;p&gt;def user_service(mocker):&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;repo = mocker.Mock()

return UserService(repo), repo
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;p&gt;def test_get_user_happy_path(user_service):&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;service, repo = user_service

repo.find_by_id.return_value = User(id="1", email="a@b.com")

result = service.get_user("1")

assert result.email == "a@b.com"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;


## Naming

- File: `test_[module_name].py`

- Function: `test_[expected_behavior]_when_[condition]`

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;p&gt;&lt;br&gt;
markdown&lt;/p&gt;


&lt;h3&gt;
  
  
  3.5 Angular Rule
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;File: &lt;code&gt;.cursor/rules/unit-test-angular.mdc&lt;/code&gt;&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight markdown"&gt;&lt;code&gt;&lt;span class="p"&gt;
---
&lt;/span&gt;
description: Angular unit test rules

globs: ["src/app/&lt;span class="gs"&gt;**/*.component.ts", "src/app/**&lt;/span&gt;/&lt;span class="ge"&gt;*.service.ts", "src/app/**/*&lt;/span&gt;.pipe.ts", "src/app/&lt;span class="ge"&gt;**&lt;/span&gt;/&lt;span class="err"&gt;*&lt;/span&gt;.guard.ts"]
&lt;span class="p"&gt;
---


&lt;/span&gt;
&lt;span class="gh"&gt;# Angular Unit Test Rules&lt;/span&gt;&lt;span class="sb"&gt;



&lt;/span&gt;&lt;span class="gu"&gt;## Library: Jest (NOT Karma — Karma is deprecated Angular 17+)&lt;/span&gt;&lt;span class="sb"&gt;



&lt;/span&gt;&lt;span class="gu"&gt;## Migration from Karma to Jest (one-time)&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;&lt;br&gt;
bash&lt;/p&gt;

&lt;p&gt;ng add @angular-builders/jest&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;


## TestBed configuration — always minimal

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;&lt;br&gt;
typescript&lt;/p&gt;

&lt;p&gt;await TestBed.configureTestingModule({&lt;/p&gt;

&lt;p&gt;imports: [ComponentUnderTest],  // standalone components&lt;/p&gt;

&lt;p&gt;providers: [&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{ provide: UserService, useValue: mockUserService }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;p&gt;]&lt;/p&gt;

&lt;p&gt;}).compileComponents();&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;


## Service mock pattern

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;&lt;br&gt;
typescript&lt;/p&gt;

&lt;p&gt;const mockUserService = {&lt;/p&gt;

&lt;p&gt;getUser: jest.fn(),&lt;/p&gt;

&lt;p&gt;createUser: jest.fn(),&lt;/p&gt;

&lt;p&gt;};&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;


## Component test — check DOM behavior, not internal state

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;&lt;br&gt;
typescript&lt;/p&gt;

&lt;p&gt;fixture.detectChanges(); // trigger ngOnInit&lt;/p&gt;

&lt;p&gt;const button = fixture.debugElement.query(By.css('[data-testid="submit"]'));&lt;/p&gt;

&lt;p&gt;button.nativeElement.click();&lt;/p&gt;

&lt;p&gt;fixture.detectChanges();&lt;/p&gt;

&lt;p&gt;expect(fixture.debugElement.query(By.css('.error-msg'))).toBeTruthy();&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;


## Pipe test — pure function, no TestBed needed

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;&lt;br&gt;
typescript&lt;/p&gt;

&lt;p&gt;it('should transform date correctly', () =&amp;gt; {&lt;/p&gt;

&lt;p&gt;const pipe = new DateFormatPipe();&lt;/p&gt;

&lt;p&gt;expect(pipe.transform(new Date('2024-01-01'))).toBe('Jan 1, 2024');&lt;/p&gt;

&lt;p&gt;});&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;


## Guard/resolver test — inject and call directly

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;&lt;br&gt;
typescript&lt;/p&gt;

&lt;p&gt;const guard = TestBed.inject(AuthGuard);&lt;/p&gt;

&lt;p&gt;const result = await guard.canActivate(mockRoute, mockState);&lt;/p&gt;

&lt;p&gt;expect(result).toBe(false);&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;&lt;br&gt;
python&lt;/p&gt;


&lt;h3&gt;
  
  
  3.6 Laravel Rule
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;File: &lt;code&gt;.cursor/rules/unit-test-laravel.mdc&lt;/code&gt;&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight markdown"&gt;&lt;code&gt;&lt;span class="p"&gt;
---
&lt;/span&gt;
description: Laravel unit test rules

globs: ["app/Services/&lt;span class="gs"&gt;**/*.php", "app/Models/**&lt;/span&gt;/&lt;span class="ge"&gt;*.php", "app/Http/Requests/**/*&lt;/span&gt;.php", "app/Actions/&lt;span class="ge"&gt;**&lt;/span&gt;/&lt;span class="err"&gt;*&lt;/span&gt;.php"]
&lt;span class="p"&gt;
---


&lt;/span&gt;
&lt;span class="gh"&gt;# Laravel Unit Test Rules&lt;/span&gt;&lt;span class="sb"&gt;



&lt;/span&gt;&lt;span class="gu"&gt;## Library: Pest (NOT PHPUnit directly — Pest wraps it with better syntax)&lt;/span&gt;&lt;span class="sb"&gt;



&lt;/span&gt;&lt;span class="gu"&gt;## File location&lt;/span&gt;
&lt;span class="p"&gt;
-&lt;/span&gt; Source: &lt;span class="sb"&gt;`app/Services/UserService.php`&lt;/span&gt;
&lt;span class="p"&gt;
-&lt;/span&gt; Test:   &lt;span class="sb"&gt;`tests/Unit/Services/UserServiceTest.php`



&lt;/span&gt;&lt;span class="gu"&gt;## Class under test — use constructor injection&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;&lt;br&gt;
php&lt;/p&gt;

&lt;p&gt;class UserService {&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;public function __construct(

    private readonly UserRepositoryInterface $repo

) {}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;p&gt;}&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;


## Mock pattern — Mockery (included with Pest/PHPUnit)

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;&lt;br&gt;
php&lt;/p&gt;

&lt;p&gt;it('throws exception when user not found', function () {&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// Arrange

$repo = Mockery::mock(UserRepositoryInterface::class);

$repo-&amp;gt;shouldReceive('findById')-&amp;gt;once()-&amp;gt;andReturn(null);

$service = new UserService($repo);



// Act &amp;amp; Assert

expect(fn () =&amp;gt; $service-&amp;gt;getUser('abc'))

    -&amp;gt;toThrow(UserNotFoundException::class);
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;p&gt;});&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;


## Data provider pattern (Pest datasets)

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;&lt;br&gt;
php&lt;/p&gt;

&lt;p&gt;it('validates email format', function (string $email, bool $valid) {&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;expect(validateEmail($email))-&amp;gt;toBe($valid);
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;p&gt;})-&amp;gt;with([&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;['valid@email.com', true],

['notanemail', false],

['', false],

['@nodomain.com', false],
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;p&gt;]);&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;


## What NOT to do in unit tests

- Never call $this-&amp;gt;get() or $this-&amp;gt;post() — that is feature testing

- Never use RefreshDatabase — that is feature/integration testing

- Never resolve from service container — inject directly

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;&lt;br&gt;
markdown&lt;/p&gt;


&lt;h2&gt;
  
  
  Part 4 — CLAUDE.md (Claude Project Memory)
&lt;/h2&gt;

&lt;p&gt;Place this at project root. Claude reads it on every session automatically.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;File: &lt;code&gt;CLAUDE.md&lt;/code&gt;&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight markdown"&gt;&lt;code&gt;
&lt;span class="gh"&gt;# Project: [Your Project Name]&lt;/span&gt;

&lt;span class="gh"&gt;# Claude Unit Test Instructions&lt;/span&gt;&lt;span class="sb"&gt;



&lt;/span&gt;&lt;span class="gu"&gt;## Stack&lt;/span&gt;
&lt;span class="p"&gt;
-&lt;/span&gt; Backend: NestJS + TypeScript
&lt;span class="p"&gt;
-&lt;/span&gt; Frontend: React + Vite + TypeScript
&lt;span class="p"&gt;
-&lt;/span&gt; Testing: Jest (NestJS) + Vitest (React) + Pest (Laravel) + pytest (Python)&lt;span class="sb"&gt;



&lt;/span&gt;&lt;span class="gu"&gt;## Unit Test Rules — NON-NEGOTIABLE&lt;/span&gt;&lt;span class="sb"&gt;



&lt;/span&gt;&lt;span class="gu"&gt;### When asked to generate a unit test:&lt;/span&gt;
&lt;span class="p"&gt;
1.&lt;/span&gt; NEVER generate integration or E2E tests unless explicitly asked
&lt;span class="p"&gt;
2.&lt;/span&gt; ALWAYS mock every external dependency
&lt;span class="p"&gt;
3.&lt;/span&gt; ALWAYS follow AAA (Arrange-Act-Assert) with comments
&lt;span class="p"&gt;
4.&lt;/span&gt; ALWAYS generate minimum 4 cases: happy path, null/empty, error thrown, edge case
&lt;span class="p"&gt;
5.&lt;/span&gt; NEVER use &lt;span class="sb"&gt;`any`&lt;/span&gt; type in TypeScript tests
&lt;span class="p"&gt;
6.&lt;/span&gt; NEVER leave &lt;span class="sb"&gt;`TODO`&lt;/span&gt; comments in generated tests&lt;span class="sb"&gt;



&lt;/span&gt;&lt;span class="gu"&gt;### Naming&lt;/span&gt;
&lt;span class="p"&gt;
-&lt;/span&gt; NestJS: &lt;span class="sb"&gt;`[name].service.spec.ts`&lt;/span&gt; inside same directory as source
&lt;span class="p"&gt;
-&lt;/span&gt; React: &lt;span class="sb"&gt;`[ComponentName].test.tsx`&lt;/span&gt; inside &lt;span class="sb"&gt;`__tests__/`&lt;/span&gt; or same directory
&lt;span class="p"&gt;
-&lt;/span&gt; Python: &lt;span class="sb"&gt;`test_[module].py`&lt;/span&gt; under &lt;span class="sb"&gt;`tests/unit/`&lt;/span&gt;
&lt;span class="p"&gt;
-&lt;/span&gt; Laravel: &lt;span class="sb"&gt;`[Name]Test.php`&lt;/span&gt; under &lt;span class="sb"&gt;`tests/Unit/`



&lt;/span&gt;&lt;span class="gu"&gt;### Test should describe BEHAVIOR, not implementation&lt;/span&gt;

GOOD: "should return empty array when no users match search"

BAD: "test getUserByFilter"&lt;span class="sb"&gt;



&lt;/span&gt;&lt;span class="gu"&gt;### If you are unsure of the correct mock structure:&lt;/span&gt;
&lt;span class="p"&gt;
-&lt;/span&gt; Ask what the dependency interface looks like
&lt;span class="p"&gt;
-&lt;/span&gt; Do NOT invent method names that don't exist in the source&lt;span class="sb"&gt;



&lt;/span&gt;&lt;span class="gu"&gt;### Coverage target: 80% lines, 75% branches per module&lt;/span&gt;&lt;span class="sb"&gt;



&lt;/span&gt;&lt;span class="gu"&gt;## Project Structure Reference&lt;/span&gt;

src/

  modules/&lt;span class="sb"&gt;

    users/

      users.service.ts

      users.service.spec.ts   ← unit test lives here

      users.repository.ts

      users.repository.spec.ts

&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Part 5 — MCP Servers for Unit Testing in Cursor + Claude
&lt;/h2&gt;

&lt;p&gt;MCP (Model Context Protocol) servers extend AI capabilities. For unit testing, these are the relevant ones:&lt;/p&gt;

&lt;h3&gt;
  
  
  5.1 Filesystem MCP (Built-in Cursor — use directly)
&lt;/h3&gt;

&lt;p&gt;Cursor already has filesystem access. No extra MCP needed to read source files and generate tests. The &lt;code&gt;.cursor/rules/&lt;/code&gt; system handles this.&lt;/p&gt;

&lt;h3&gt;
  
  
  5.2 Available MCP Servers for Testing Workflows
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;1. &lt;code&gt;@executeautomation/playwright-mcp-server&lt;/code&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Scope: E2E only — not relevant for unit tests&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Skip for this use case&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;2. &lt;code&gt;@modelcontextprotocol/server-filesystem&lt;/code&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Gives Claude access to project files&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Use in Claude Desktop to read source → generate tests&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Install: configured in &lt;code&gt;claude_desktop_config.json&lt;/code&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;3. Custom Testing MCP (Build This — Highest Value)&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Build a lightweight MCP server that:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Reads a source file&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Extracts function signatures + types&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Returns structured JSON to Claude&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Claude generates tests from structure, not guesswork&lt;br&gt;
&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;
&lt;span class="c1"&gt;// mcp-test-generator/src/index.ts&lt;/span&gt;

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;Server&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@modelcontextprotocol/sdk/server/index.js&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;StdioServerTransport&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@modelcontextprotocol/sdk/server/stdio.js&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nx"&gt;ts&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;typescript&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;



&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;server&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Server&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;test-generator&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;version&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;1.0.0&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;

  &lt;span class="na"&gt;capabilities&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;tools&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="p"&gt;});&lt;/span&gt;



&lt;span class="nx"&gt;server&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setRequestHandler&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;tools/call&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;

  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;params&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;extract_signatures&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;

    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;filePath&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;params&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;arguments&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;signatures&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;extractFunctionSignatures&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;filePath&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// parse AST&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;content&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[{&lt;/span&gt; &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;text&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;text&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;stringify&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;signatures&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;}]&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;

  &lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="p"&gt;});&lt;/span&gt;



&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;extractFunctionSignatures&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;filePath&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;

  &lt;span class="c1"&gt;// Use TypeScript compiler API to extract:&lt;/span&gt;

  &lt;span class="c1"&gt;// - class name&lt;/span&gt;

  &lt;span class="c1"&gt;// - method names&lt;/span&gt;

  &lt;span class="c1"&gt;// - parameter types&lt;/span&gt;

  &lt;span class="c1"&gt;// - return types&lt;/span&gt;

  &lt;span class="c1"&gt;// - injected dependencies (constructor params)&lt;/span&gt;

  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;program&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;ts&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;createProgram&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="nx"&gt;filePath&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="p"&gt;{});&lt;/span&gt;

  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;sourceFile&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;program&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getSourceFile&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;filePath&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="c1"&gt;// ... AST traversal&lt;/span&gt;

  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;className&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;methods&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;dependencies&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="p"&gt;}&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Why this matters:&lt;/strong&gt; When Claude receives typed signatures instead of raw source code, it cannot hallucinate — it generates tests from concrete types, not guesses.&lt;/p&gt;

&lt;h3&gt;
  
  
  5.3 Claude Desktop MCP Config
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="err"&gt;//&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;~/Library/Application&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;Support/Claude/claude_desktop_config.json&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;(macOS)&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="err"&gt;//&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;%APPDATA%\Claude\claude_desktop_config.json&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;(Windows)&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;

  &lt;/span&gt;&lt;span class="nl"&gt;"mcpServers"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;

    &lt;/span&gt;&lt;span class="nl"&gt;"filesystem"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;

      &lt;/span&gt;&lt;span class="nl"&gt;"command"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"npx"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;

      &lt;/span&gt;&lt;span class="nl"&gt;"args"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"-y"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"@modelcontextprotocol/server-filesystem"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"/path/to/your/project"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;

    &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;

    &lt;/span&gt;&lt;span class="nl"&gt;"test-generator"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;

      &lt;/span&gt;&lt;span class="nl"&gt;"command"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"node"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;

      &lt;/span&gt;&lt;span class="nl"&gt;"args"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"/path/to/your/mcp-test-generator/dist/index.js"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;

    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;

  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  5.4 Cursor MCP Config
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="err"&gt;//&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;.cursor/mcp.json&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;(project-level)&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;

  &lt;/span&gt;&lt;span class="nl"&gt;"mcpServers"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;

    &lt;/span&gt;&lt;span class="nl"&gt;"test-generator"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;

      &lt;/span&gt;&lt;span class="nl"&gt;"command"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"node"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;

      &lt;/span&gt;&lt;span class="nl"&gt;"args"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"./tools/mcp-test-generator/dist/index.js"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;

    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;

  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Part 6 — Anti-Hallucination Prompt Templates
&lt;/h2&gt;

&lt;p&gt;The root cause of AI hallucination in tests: AI invents method names, wrong mock structures, non-existent imports. These prompts eliminate that.&lt;/p&gt;

&lt;h3&gt;
  
  
  6.1 Cursor Cmd+K Prompt (Use This Exactly)
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;
Generate a unit &lt;span class="nb"&gt;test &lt;/span&gt;file &lt;span class="k"&gt;for &lt;/span&gt;this &lt;span class="o"&gt;[&lt;/span&gt;NestJS service / React component / Python class / Angular service / Laravel service].



Rules:

- Library: &lt;span class="o"&gt;[&lt;/span&gt;Jest / Vitest / pytest / Jest / Pest]

- Test only THIS file — no integration

- Mock ALL dependencies listed &lt;span class="k"&gt;in &lt;/span&gt;the constructor/props

- Follow AAA pattern with comments

- Minimum 4 &lt;span class="nb"&gt;test &lt;/span&gt;cases per public method

- Use ONLY methods/properties that exist &lt;span class="k"&gt;in &lt;/span&gt;this &lt;span class="nb"&gt;source &lt;/span&gt;file

- Do NOT import anything not shown &lt;span class="k"&gt;in &lt;/span&gt;the &lt;span class="nb"&gt;source&lt;/span&gt;

- Naming: &lt;span class="s2"&gt;"should [behavior] when [condition]"&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  6.2 Claude Prompt (For CLAUDE.md aware sessions)
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight markdown"&gt;&lt;code&gt;
Read [filename].

Extract:
&lt;span class="p"&gt;
1.&lt;/span&gt; Class/function name
&lt;span class="p"&gt;
2.&lt;/span&gt; All public methods with parameter types and return types
&lt;span class="p"&gt;
3.&lt;/span&gt; All constructor dependencies (for mocking)&lt;span class="sb"&gt;



&lt;/span&gt;Then generate the unit test file following CLAUDE.md rules.

Do NOT assume any method exists unless you can see it in the source.

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  6.3 Batch Test Generation Prompt
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;
&lt;span class="k"&gt;For&lt;/span&gt; &lt;span class="n"&gt;each&lt;/span&gt; &lt;span class="n"&gt;file&lt;/span&gt; &lt;span class="n"&gt;in&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;directory&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="n"&gt;generate&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="n"&gt;corresponding&lt;/span&gt; &lt;span class="mf"&gt;.&lt;/span&gt;&lt;span class="n"&gt;spec&lt;/span&gt;&lt;span class="mf"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ts&lt;/span&gt; &lt;span class="n"&gt;file&lt;/span&gt;&lt;span class="mf"&gt;.&lt;/span&gt;

&lt;span class="nc"&gt;Process&lt;/span&gt; &lt;span class="n"&gt;one&lt;/span&gt; &lt;span class="n"&gt;file&lt;/span&gt; &lt;span class="n"&gt;at&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="mf"&gt;.&lt;/span&gt;

&lt;span class="k"&gt;For&lt;/span&gt; &lt;span class="n"&gt;each&lt;/span&gt; &lt;span class="n"&gt;file&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;

  &lt;span class="mf"&gt;1.&lt;/span&gt; &lt;span class="nc"&gt;Read&lt;/span&gt; &lt;span class="n"&gt;the&lt;/span&gt; &lt;span class="n"&gt;source&lt;/span&gt;

  &lt;span class="mf"&gt;2.&lt;/span&gt; &lt;span class="k"&gt;List&lt;/span&gt; &lt;span class="n"&gt;the&lt;/span&gt; &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;methods&lt;/span&gt; &lt;span class="n"&gt;you&lt;/span&gt; &lt;span class="nf"&gt;found&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;confirm&lt;/span&gt; &lt;span class="n"&gt;before&lt;/span&gt; &lt;span class="n"&gt;generating&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

  &lt;span class="mf"&gt;3.&lt;/span&gt; &lt;span class="nc"&gt;Generate&lt;/span&gt; &lt;span class="n"&gt;the&lt;/span&gt; &lt;span class="n"&gt;test&lt;/span&gt; &lt;span class="n"&gt;file&lt;/span&gt;

  &lt;span class="mf"&gt;4.&lt;/span&gt; &lt;span class="nc"&gt;Show&lt;/span&gt; &lt;span class="n"&gt;the&lt;/span&gt; &lt;span class="n"&gt;test&lt;/span&gt; &lt;span class="n"&gt;file&lt;/span&gt; &lt;span class="n"&gt;path&lt;/span&gt;



&lt;span class="k"&gt;Do&lt;/span&gt; &lt;span class="n"&gt;not&lt;/span&gt; &lt;span class="n"&gt;proceed&lt;/span&gt; &lt;span class="n"&gt;to&lt;/span&gt; &lt;span class="n"&gt;the&lt;/span&gt; &lt;span class="n"&gt;next&lt;/span&gt; &lt;span class="n"&gt;file&lt;/span&gt; &lt;span class="n"&gt;until&lt;/span&gt; &lt;span class="n"&gt;the&lt;/span&gt; &lt;span class="n"&gt;current&lt;/span&gt; &lt;span class="n"&gt;one&lt;/span&gt; &lt;span class="n"&gt;is&lt;/span&gt; &lt;span class="n"&gt;confirmed&lt;/span&gt;&lt;span class="mf"&gt;.&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Part 7 — Project Structure Convention
&lt;/h2&gt;

&lt;p&gt;All stacks follow the same proximity principle: &lt;strong&gt;test file lives next to source file&lt;/strong&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Node.js / NestJS / Angular
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight markdown"&gt;&lt;code&gt;
src/

  modules/&lt;span class="sb"&gt;

    users/

      users.service.ts

      users.service.spec.ts        ← unit test

      users.repository.ts

      users.repository.spec.ts     ← unit test

      users.guard.ts

      users.guard.spec.ts          ← unit test

&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  React
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
src/

  components/

    UserCard/

      UserCard.tsx

      UserCard.test.tsx            ← unit test

      UserCard.stories.tsx         ← storybook (optional)

  hooks/

    useUserData.ts

    useUserData.test.ts            ← unit test

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Python
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
app/

  services/

    user_service.py

tests/

  unit/

    services/

      test_user_service.py        ← mirrors app/ structure

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Laravel
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
app/

  Services/

    UserService.php

tests/

  Unit/

    Services/

      UserServiceTest.php         ← mirrors app/ structure

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Part 8 — CI Enforcement
&lt;/h2&gt;

&lt;p&gt;All of this means nothing without enforcement. The pipeline is the final gate.&lt;/p&gt;

&lt;h3&gt;
  
  
  GitHub Actions — Multi-stack parallel
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;
&lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Unit Tests&lt;/span&gt;



&lt;span class="na"&gt;on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;push&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;pull_request&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;



&lt;span class="na"&gt;jobs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;

  &lt;span class="na"&gt;nestjs-unit&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;

    &lt;span class="na"&gt;runs-on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;ubuntu-latest&lt;/span&gt;

    &lt;span class="na"&gt;steps&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;

      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;actions/checkout@v4&lt;/span&gt;

      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;actions/setup-node@v4&lt;/span&gt;

        &lt;span class="na"&gt;with&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;{&lt;/span&gt; &lt;span class="nv"&gt;node-version&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;20'&lt;/span&gt; &lt;span class="pi"&gt;}&lt;/span&gt;

      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;npm ci&lt;/span&gt;

      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;npm run test:unit -- --coverage --coverageThreshold='{"global":{"lines":80}}'&lt;/span&gt;



  &lt;span class="na"&gt;react-unit&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;

    &lt;span class="na"&gt;runs-on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;ubuntu-latest&lt;/span&gt;

    &lt;span class="na"&gt;steps&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;

      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;actions/checkout@v4&lt;/span&gt;

      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;actions/setup-node@v4&lt;/span&gt;

        &lt;span class="na"&gt;with&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;{&lt;/span&gt; &lt;span class="nv"&gt;node-version&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;20'&lt;/span&gt; &lt;span class="pi"&gt;}&lt;/span&gt;

      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;npm ci&lt;/span&gt;

      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;npx vitest run --coverage&lt;/span&gt;



  &lt;span class="na"&gt;python-unit&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;

    &lt;span class="na"&gt;runs-on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;ubuntu-latest&lt;/span&gt;

    &lt;span class="na"&gt;steps&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;

      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;actions/checkout@v4&lt;/span&gt;

      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;actions/setup-python@v5&lt;/span&gt;

        &lt;span class="na"&gt;with&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;{&lt;/span&gt; &lt;span class="nv"&gt;python-version&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;3.12'&lt;/span&gt; &lt;span class="pi"&gt;}&lt;/span&gt;

      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;pip install -r requirements-dev.txt&lt;/span&gt;

      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;pytest tests/unit/ --cov=app --cov-fail-under=80&lt;/span&gt;



  &lt;span class="na"&gt;laravel-unit&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;

    &lt;span class="na"&gt;runs-on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;ubuntu-latest&lt;/span&gt;

    &lt;span class="na"&gt;steps&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;

      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;actions/checkout@v4&lt;/span&gt;

      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;shivammathur/setup-php@v2&lt;/span&gt;

        &lt;span class="na"&gt;with&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;{&lt;/span&gt; &lt;span class="nv"&gt;php-version&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;8.3'&lt;/span&gt; &lt;span class="pi"&gt;}&lt;/span&gt;

      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;composer install&lt;/span&gt;

      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;./vendor/bin/pest --coverage --min=80&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Pre-commit Hook (Husky — Node stacks)
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="err"&gt;//&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;package.json&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;

  &lt;/span&gt;&lt;span class="nl"&gt;"lint-staged"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;

    &lt;/span&gt;&lt;span class="nl"&gt;"src/**/*.service.ts"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"jest --findRelatedTests --passWithNoTests"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;

    &lt;/span&gt;&lt;span class="nl"&gt;"src/**/*.tsx"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"vitest related --run"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;

  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Part 9 — Quick Start Checklist
&lt;/h2&gt;

&lt;h3&gt;
  
  
  New Project
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
□ Install test library (one per stack — see Part 1)

□ Configure jest.config.ts / vitest.config.ts / pytest.ini / pest.php

□ Create .cursor/rules/ directory with all rule files from Part 3

□ Create CLAUDE.md at project root from Part 4

□ Add coverage thresholds to config

□ Add pre-commit hooks (Husky for Node, pre-commit for Python)

□ Add CI workflow from Part 8

□ Create test factory files (one per major entity)

□ Write first failing test → implement → green → commit

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Existing Project
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
□ Add test library without touching existing code

□ Add .cursor/rules/ + CLAUDE.md

□ Run coverage on existing code → document current baseline

□ Pick 3 critical services → generate tests → set as new baseline

□ Add CI with threshold = current baseline (not ideal — current)

□ Raise threshold by 5% per sprint

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Appendix — Install Commands Per Stack
&lt;/h2&gt;

&lt;h3&gt;
  
  
  NestJS
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;
npm &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;--save-dev&lt;/span&gt; jest ts-jest @types/jest @nestjs/testing jest-mock-extended @golevelup/ts-jest

npx ts-jest config:init

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  React (Vite)
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;
npm &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;--save-dev&lt;/span&gt; vitest @vitest/coverage-v8 @testing-library/react @testing-library/user-event @testing-library/jest-dom jsdom

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Python
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;
pip &lt;span class="nb"&gt;install &lt;/span&gt;pytest pytest-cov pytest-mock pytest-asyncio factory-boy

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Angular
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;
ng add @angular-builders/jest

npm &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;--save-dev&lt;/span&gt; jest jest-preset-angular @types/jest

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Laravel
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;
composer require pestphp/pest pestphp/pest-plugin-laravel &lt;span class="nt"&gt;--dev&lt;/span&gt;

./vendor/bin/pest &lt;span class="nt"&gt;--init&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;p&gt;&lt;em&gt;Last updated: 2025 — verify library major versions before adopting&lt;/em&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>testing</category>
      <category>tutorial</category>
      <category>webdev</category>
    </item>
    <item>
      <title>Unit Test AI Guide — Zero Hallucination, Cross-Stack Standard</title>
      <dc:creator>Bhaumik</dc:creator>
      <pubDate>Fri, 19 Jun 2026 12:14:44 +0000</pubDate>
      <link>https://dev.to/bhaumik-viitor/unit-test-ai-guide-zero-hallucination-cross-stack-standard-4mb2</link>
      <guid>https://dev.to/bhaumik-viitor/unit-test-ai-guide-zero-hallucination-cross-stack-standard-4mb2</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Focus:&lt;/strong&gt; Unit Tests ONLY — no integration, no E2E  &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Stacks:&lt;/strong&gt; Node.js (NestJS/Express) · React.js · Python · Angular · Laravel  &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Goal:&lt;/strong&gt; AI generates unit tests consistently, deterministically, without hallucination  &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;IDE:&lt;/strong&gt; Cursor (Primary) + Claude (Secondary)&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  Part 1 — Best Single Library Per Stack (Final Decision)
&lt;/h2&gt;

&lt;p&gt;Do not mix libraries. Pick one per stack, configure it fully, never deviate.&lt;/p&gt;

&lt;p&gt;| Stack | Library | Why This One |&lt;/p&gt;

&lt;p&gt;|---|---|---|&lt;/p&gt;

&lt;p&gt;| &lt;strong&gt;Node.js / NestJS / Express&lt;/strong&gt; | &lt;code&gt;Jest&lt;/code&gt; | Native DI mocking, &lt;code&gt;@nestjs/testing&lt;/code&gt; built around it, widest ecosystem |&lt;/p&gt;

&lt;p&gt;| &lt;strong&gt;React.js&lt;/strong&gt; | &lt;code&gt;Vitest&lt;/code&gt; + &lt;code&gt;@testing-library/react&lt;/code&gt; | Native Vite/ESM support, Jest-compatible API, 3–10x faster |&lt;/p&gt;

&lt;p&gt;| &lt;strong&gt;Python&lt;/strong&gt; | &lt;code&gt;pytest&lt;/code&gt; | De facto standard, fixture system eliminates boilerplate, best plugin ecosystem |&lt;/p&gt;

&lt;p&gt;| &lt;strong&gt;Angular&lt;/strong&gt; | &lt;code&gt;Jest&lt;/code&gt; (replace Karma) | Karma is deprecated in Angular 17+; Jest is the official migration target |&lt;/p&gt;

&lt;p&gt;| &lt;strong&gt;Laravel&lt;/strong&gt; | &lt;code&gt;Pest&lt;/code&gt; | Modern syntax, built on PHPUnit, higher signal-to-noise ratio |&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Rule:&lt;/strong&gt; If someone suggests a second library for the same stack, reject it. One library per stack, configured once, followed always.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  Part 2 — IDE: Cursor (Only Choice for This Goal)
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Why Cursor and Not VS Code / WebStorm
&lt;/h3&gt;

&lt;p&gt;| Capability | Cursor | VS Code + Copilot | WebStorm |&lt;/p&gt;

&lt;p&gt;|---|---|---|---|&lt;/p&gt;

&lt;p&gt;| Project-level AI rules | ✅ &lt;code&gt;.cursor/rules/&lt;/code&gt; | ❌ | ❌ |&lt;/p&gt;

&lt;p&gt;| Codebase-aware context | ✅ &lt;code&gt;@codebase&lt;/code&gt; | Partial | Partial |&lt;/p&gt;

&lt;p&gt;| Run terminal + read output | ✅ Composer | ❌ | ❌ |&lt;/p&gt;

&lt;p&gt;| Multi-file generation | ✅ Agent mode | Limited | ❌ |&lt;/p&gt;

&lt;p&gt;| Custom instructions per filetype | ✅ | ❌ | ❌ |&lt;/p&gt;

&lt;p&gt;| MCP server integration | ✅ | ❌ | ❌ |&lt;/p&gt;

&lt;p&gt;Cursor's &lt;code&gt;.cursor/rules/&lt;/code&gt; system is the &lt;strong&gt;only IDE-native mechanism&lt;/strong&gt; that injects persistent, project-scoped instructions into every AI interaction — this is what prevents hallucination at the source.&lt;/p&gt;

&lt;h3&gt;
  
  
  Cursor Setup for This Project
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
project-root/

├── .cursor/

│   └── rules/

│       ├── unit-test-global.mdc       ← applies to all files

│       ├── unit-test-nestjs.mdc       ← applies to *.service.ts, *.guard.ts

│       ├── unit-test-react.mdc        ← applies to *.tsx, *.component.tsx

│       ├── unit-test-python.mdc       ← applies to *.py

│       ├── unit-test-angular.mdc      ← applies to *.component.ts, *.service.ts

│       └── unit-test-laravel.mdc      ← applies to *Service.php, *Model.php

├── CLAUDE.md                          ← Claude project memory file

└── ...

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Part 3 — Cursor Rules Files (Anti-Hallucination Core)
&lt;/h2&gt;

&lt;p&gt;These files are injected into every AI prompt automatically when working on matching files.&lt;/p&gt;

&lt;h3&gt;
  
  
  3.1 Global Unit Test Rule
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;File: &lt;code&gt;.cursor/rules/unit-test-global.mdc&lt;/code&gt;&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight markdown"&gt;&lt;code&gt;&lt;span class="p"&gt;
---
&lt;/span&gt;
description: Global unit test rules — applies to all files in this project

globs: ["&lt;span class="gs"&gt;**/*.spec.ts", "**&lt;/span&gt;/&lt;span class="ge"&gt;*.test.ts", "**/*&lt;/span&gt;.spec.tsx", "&lt;span class="gs"&gt;**/*_test.py", "**&lt;/span&gt;/Test&lt;span class="err"&gt;*&lt;/span&gt;.php"]

alwaysApply: true
&lt;span class="p"&gt;
---


&lt;/span&gt;
&lt;span class="gh"&gt;# Unit Test Contract — MUST FOLLOW, NO EXCEPTIONS&lt;/span&gt;&lt;span class="sb"&gt;



&lt;/span&gt;&lt;span class="gu"&gt;## What is a unit test here&lt;/span&gt;
&lt;span class="p"&gt;
-&lt;/span&gt; Tests ONE class or function in complete isolation
&lt;span class="p"&gt;
-&lt;/span&gt; ALL external dependencies are mocked — no real DB, no real HTTP, no real file system
&lt;span class="p"&gt;
-&lt;/span&gt; Each test runs independently — no shared mutable state between tests
&lt;span class="p"&gt;
-&lt;/span&gt; Runs in &amp;lt; 100ms&lt;span class="sb"&gt;



&lt;/span&gt;&lt;span class="gu"&gt;## Structure: AAA — Always, Without Exception&lt;/span&gt;

Every test MUST have these three sections, with comments:

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;// Arrange — set up inputs, mocks, expected values&lt;/p&gt;

&lt;p&gt;// Act — call the single function/method under test&lt;/p&gt;

&lt;p&gt;// Assert — verify exactly one outcome&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;


## Naming Convention — Mandatory

- File: `[module-name].spec.ts` or `[module-name].unit.spec.ts`

- Describe block: exact class or function name

- It/test block: "should [expected behavior] when [specific condition]"

  GOOD: "should throw NotFoundException when user does not exist"

  BAD:  "user not found", "test 1", "works correctly"



## What to test per function — minimum coverage

1. Happy path — valid input → expected output

2. Null/undefined input — how does it fail safely

3. Empty input — empty string, empty array, zero

4. Error path — when dependency throws, what happens

5. Boundary — max length, negative numbers, boolean edge



## What NOT to include in unit tests

- Database queries (mock the repository)

- HTTP calls (mock the service/axios/fetch)

- File system operations (mock fs)

- Timer behavior (use jest.useFakeTimers)

- Random values (mock Math.random or faker with fixed seed)



## AI Instruction

When asked to generate a unit test:

1. READ the function signature and types first

2. IDENTIFY all dependencies (constructor args, imported modules)

3. MOCK every dependency — never use real implementations

4. Generate minimum 4 test cases per method (happy, null, error, edge)

5. NEVER import from test doubles or assume what isn't in the source file

6. If you are unsure of a type — ASK, do not assume

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h3&gt;
  
  
  3.2 NestJS Rule
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;File: &lt;code&gt;.cursor/rules/unit-test-nestjs.mdc&lt;/code&gt;&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight markdown"&gt;&lt;code&gt;&lt;span class="p"&gt;
---
&lt;/span&gt;
description: NestJS unit test rules

globs: ["src/&lt;span class="gs"&gt;**/*.service.ts", "src/**&lt;/span&gt;/&lt;span class="ge"&gt;*.guard.ts", "src/**/*&lt;/span&gt;.interceptor.ts", "src/&lt;span class="ge"&gt;**&lt;/span&gt;/&lt;span class="err"&gt;*&lt;/span&gt;.pipe.ts"]
&lt;span class="p"&gt;
---


&lt;/span&gt;
&lt;span class="gh"&gt;# NestJS Unit Test Rules&lt;/span&gt;&lt;span class="sb"&gt;



&lt;/span&gt;&lt;span class="gu"&gt;## Library: Jest + @nestjs/testing + jest-mock-extended&lt;/span&gt;&lt;span class="sb"&gt;



&lt;/span&gt;&lt;span class="gu"&gt;## Always use Test.createTestingModule&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;&lt;br&gt;
typescript&lt;/p&gt;

&lt;p&gt;const module = await Test.createTestingModule({&lt;/p&gt;

&lt;p&gt;providers: [&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;SubjectService,

{ provide: DependencyService, useValue: mockDependency }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;p&gt;]&lt;/p&gt;

&lt;p&gt;}).compile();&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;


## Mock Pattern — jest-mock-extended

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;&lt;br&gt;
typescript&lt;/p&gt;

&lt;p&gt;import { createMock } from '@golevelup/ts-jest';&lt;/p&gt;

&lt;p&gt;// OR&lt;/p&gt;

&lt;p&gt;import { mock } from 'jest-mock-extended';&lt;/p&gt;

&lt;p&gt;const mockUserRepo = mock();&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;


## Never

- Never use `new SubjectService()` directly — always use TestingModule

- Never let `useValue` contain real implementations

- Never test more than one service per describe block



## Repository Mock Template

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;&lt;br&gt;
typescript&lt;/p&gt;

&lt;p&gt;const mockRepo = {&lt;/p&gt;

&lt;p&gt;findOne: jest.fn(),&lt;/p&gt;

&lt;p&gt;save: jest.fn(),&lt;/p&gt;

&lt;p&gt;delete: jest.fn(),&lt;/p&gt;

&lt;p&gt;findAll: jest.fn(),&lt;/p&gt;

&lt;p&gt;update: jest.fn(),&lt;/p&gt;

&lt;p&gt;};&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;


## Required imports for every NestJS spec file

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;&lt;br&gt;
typescript&lt;/p&gt;

&lt;p&gt;import { Test, TestingModule } from '@nestjs/testing';&lt;/p&gt;

&lt;p&gt;import { NotFoundException, BadRequestException } from '@nestjs/common';&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;&lt;br&gt;
markdown&lt;/p&gt;


&lt;h3&gt;
  
  
  3.3 React Rule
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;File: &lt;code&gt;.cursor/rules/unit-test-react.mdc&lt;/code&gt;&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight markdown"&gt;&lt;code&gt;&lt;span class="p"&gt;
---
&lt;/span&gt;
description: React unit test rules

globs: ["src/&lt;span class="gs"&gt;**/*.tsx", "src/**&lt;/span&gt;/&lt;span class="ge"&gt;*.component.tsx", "src/hooks/**/*&lt;/span&gt;.ts"]
&lt;span class="p"&gt;
---


&lt;/span&gt;
&lt;span class="gh"&gt;# React Unit Test Rules&lt;/span&gt;&lt;span class="sb"&gt;



&lt;/span&gt;&lt;span class="gu"&gt;## Library: Vitest + @testing-library/react + @testing-library/user-event&lt;/span&gt;&lt;span class="sb"&gt;



&lt;/span&gt;&lt;span class="gu"&gt;## Required setup in vitest.config.ts&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;&lt;br&gt;
typescript&lt;/p&gt;

&lt;p&gt;export default defineConfig({&lt;/p&gt;

&lt;p&gt;test: {&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;environment: 'jsdom',

globals: true,

setupFiles: ['./src/test/setup.ts']
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;p&gt;}&lt;/p&gt;

&lt;p&gt;})&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;


## setup.ts

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;&lt;br&gt;
typescript&lt;/p&gt;

&lt;p&gt;import '@testing-library/jest-dom';&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;


## Component test structure

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;&lt;br&gt;
typescript&lt;/p&gt;

&lt;p&gt;import { render, screen } from '@testing-library/react';&lt;/p&gt;

&lt;p&gt;import userEvent from '@testing-library/user-event';&lt;/p&gt;

&lt;p&gt;import { vi } from 'vitest';&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;


## Mocking rules for React

- Mock ALL hooks that call APIs: `vi.mock('../hooks/useUsers')`

- Mock ALL context providers — wrap with test-specific providers

- Mock router: use `MemoryRouter` from react-router-dom

- NEVER mock internal state (useState) — test behavior, not implementation



## Query priority (RTL best practice — mandatory)

1. getByRole — prefer always

2. getByLabelText — for forms

3. getByText — for content

4. getByTestId — LAST RESORT only, requires data-testid attribute



## User event — always use userEvent, never fireEvent

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;&lt;br&gt;
typescript&lt;/p&gt;

&lt;p&gt;const user = userEvent.setup();&lt;/p&gt;

&lt;p&gt;await user.click(button);&lt;/p&gt;

&lt;p&gt;await user.type(input, 'value');&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;


## Custom hook testing

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;&lt;br&gt;
typescript&lt;/p&gt;

&lt;p&gt;import { renderHook, act } from '@testing-library/react';&lt;/p&gt;

&lt;p&gt;const { result } = renderHook(() =&amp;gt; useMyHook());&lt;/p&gt;

&lt;p&gt;act(() =&amp;gt; result.current.doSomething());&lt;/p&gt;

&lt;p&gt;expect(result.current.value).toBe('expected');&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;&lt;br&gt;
typescript&lt;/p&gt;


&lt;h3&gt;
  
  
  3.4 Python Rule
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;File: &lt;code&gt;.cursor/rules/unit-test-python.mdc&lt;/code&gt;&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight markdown"&gt;&lt;code&gt;&lt;span class="p"&gt;
---
&lt;/span&gt;
description: Python unit test rules

globs: ["&lt;span class="gs"&gt;**/*.py", "!**&lt;/span&gt;/&lt;span class="ge"&gt;*migrations*&lt;/span&gt;"]
&lt;span class="p"&gt;
---


&lt;/span&gt;
&lt;span class="gh"&gt;# Python Unit Test Rules&lt;/span&gt;&lt;span class="sb"&gt;



&lt;/span&gt;&lt;span class="gu"&gt;## Library: pytest + pytest-mock + factory-boy&lt;/span&gt;&lt;span class="sb"&gt;



&lt;/span&gt;&lt;span class="gu"&gt;## File naming&lt;/span&gt;
&lt;span class="p"&gt;
-&lt;/span&gt; Source: &lt;span class="sb"&gt;`app/services/user_service.py`&lt;/span&gt;
&lt;span class="p"&gt;
-&lt;/span&gt; Test:   &lt;span class="sb"&gt;`tests/unit/test_user_service.py`&lt;/span&gt;
&lt;span class="p"&gt;
-&lt;/span&gt; ALWAYS mirror the source directory structure under tests/unit/&lt;span class="sb"&gt;



&lt;/span&gt;&lt;span class="gu"&gt;## Class under test — always use dependency injection&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;&lt;br&gt;
python&lt;/p&gt;
&lt;h1&gt;
  
  
  GOOD — injectable dependency
&lt;/h1&gt;

&lt;p&gt;class UserService:&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;def __init__(self, repo: UserRepository):

    self.repo = repo
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;h1&gt;
  
  
  BAD — untestable
&lt;/h1&gt;

&lt;p&gt;class UserService:&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;def __init__(self):

    self.repo = UserRepository()  # can't mock this
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;


## Mock pattern — pytest-mock (mocker fixture)

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;p&gt;&lt;br&gt;
python&lt;/p&gt;

&lt;p&gt;def test_raises_when_user_not_found(mocker):&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;mock_repo = mocker.Mock()

mock_repo.find_by_id.return_value = None

service = UserService(mock_repo)

with pytest.raises(UserNotFoundException):

    service.get_user("missing-id")
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;


## Async tests — pytest-asyncio

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;p&gt;&lt;br&gt;
python&lt;/p&gt;

&lt;p&gt;import pytest&lt;/p&gt;

&lt;p&gt;@pytest.mark.asyncio&lt;/p&gt;

&lt;p&gt;async def test_async_service(mocker):&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;mock_repo = mocker.AsyncMock()

...
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;


## Fixture pattern — for shared setup

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;p&gt;&lt;br&gt;
python&lt;/p&gt;

&lt;p&gt;@pytest.fixture&lt;/p&gt;

&lt;p&gt;def user_service(mocker):&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;repo = mocker.Mock()

return UserService(repo), repo
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;p&gt;def test_get_user_happy_path(user_service):&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;service, repo = user_service

repo.find_by_id.return_value = User(id="1", email="a@b.com")

result = service.get_user("1")

assert result.email == "a@b.com"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;


## Naming

- File: `test_[module_name].py`

- Function: `test_[expected_behavior]_when_[condition]`

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;p&gt;&lt;br&gt;
markdown&lt;/p&gt;


&lt;h3&gt;
  
  
  3.5 Angular Rule
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;File: &lt;code&gt;.cursor/rules/unit-test-angular.mdc&lt;/code&gt;&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight markdown"&gt;&lt;code&gt;&lt;span class="p"&gt;
---
&lt;/span&gt;
description: Angular unit test rules

globs: ["src/app/&lt;span class="gs"&gt;**/*.component.ts", "src/app/**&lt;/span&gt;/&lt;span class="ge"&gt;*.service.ts", "src/app/**/*&lt;/span&gt;.pipe.ts", "src/app/&lt;span class="ge"&gt;**&lt;/span&gt;/&lt;span class="err"&gt;*&lt;/span&gt;.guard.ts"]
&lt;span class="p"&gt;
---


&lt;/span&gt;
&lt;span class="gh"&gt;# Angular Unit Test Rules&lt;/span&gt;&lt;span class="sb"&gt;



&lt;/span&gt;&lt;span class="gu"&gt;## Library: Jest (NOT Karma — Karma is deprecated Angular 17+)&lt;/span&gt;&lt;span class="sb"&gt;



&lt;/span&gt;&lt;span class="gu"&gt;## Migration from Karma to Jest (one-time)&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;&lt;br&gt;
bash&lt;/p&gt;

&lt;p&gt;ng add @angular-builders/jest&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;


## TestBed configuration — always minimal

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;&lt;br&gt;
typescript&lt;/p&gt;

&lt;p&gt;await TestBed.configureTestingModule({&lt;/p&gt;

&lt;p&gt;imports: [ComponentUnderTest],  // standalone components&lt;/p&gt;

&lt;p&gt;providers: [&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{ provide: UserService, useValue: mockUserService }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;p&gt;]&lt;/p&gt;

&lt;p&gt;}).compileComponents();&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;


## Service mock pattern

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;&lt;br&gt;
typescript&lt;/p&gt;

&lt;p&gt;const mockUserService = {&lt;/p&gt;

&lt;p&gt;getUser: jest.fn(),&lt;/p&gt;

&lt;p&gt;createUser: jest.fn(),&lt;/p&gt;

&lt;p&gt;};&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;


## Component test — check DOM behavior, not internal state

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;&lt;br&gt;
typescript&lt;/p&gt;

&lt;p&gt;fixture.detectChanges(); // trigger ngOnInit&lt;/p&gt;

&lt;p&gt;const button = fixture.debugElement.query(By.css('[data-testid="submit"]'));&lt;/p&gt;

&lt;p&gt;button.nativeElement.click();&lt;/p&gt;

&lt;p&gt;fixture.detectChanges();&lt;/p&gt;

&lt;p&gt;expect(fixture.debugElement.query(By.css('.error-msg'))).toBeTruthy();&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;


## Pipe test — pure function, no TestBed needed

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;&lt;br&gt;
typescript&lt;/p&gt;

&lt;p&gt;it('should transform date correctly', () =&amp;gt; {&lt;/p&gt;

&lt;p&gt;const pipe = new DateFormatPipe();&lt;/p&gt;

&lt;p&gt;expect(pipe.transform(new Date('2024-01-01'))).toBe('Jan 1, 2024');&lt;/p&gt;

&lt;p&gt;});&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;


## Guard/resolver test — inject and call directly

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;&lt;br&gt;
typescript&lt;/p&gt;

&lt;p&gt;const guard = TestBed.inject(AuthGuard);&lt;/p&gt;

&lt;p&gt;const result = await guard.canActivate(mockRoute, mockState);&lt;/p&gt;

&lt;p&gt;expect(result).toBe(false);&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;&lt;br&gt;
python&lt;/p&gt;


&lt;h3&gt;
  
  
  3.6 Laravel Rule
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;File: &lt;code&gt;.cursor/rules/unit-test-laravel.mdc&lt;/code&gt;&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight markdown"&gt;&lt;code&gt;&lt;span class="p"&gt;
---
&lt;/span&gt;
description: Laravel unit test rules

globs: ["app/Services/&lt;span class="gs"&gt;**/*.php", "app/Models/**&lt;/span&gt;/&lt;span class="ge"&gt;*.php", "app/Http/Requests/**/*&lt;/span&gt;.php", "app/Actions/&lt;span class="ge"&gt;**&lt;/span&gt;/&lt;span class="err"&gt;*&lt;/span&gt;.php"]
&lt;span class="p"&gt;
---


&lt;/span&gt;
&lt;span class="gh"&gt;# Laravel Unit Test Rules&lt;/span&gt;&lt;span class="sb"&gt;



&lt;/span&gt;&lt;span class="gu"&gt;## Library: Pest (NOT PHPUnit directly — Pest wraps it with better syntax)&lt;/span&gt;&lt;span class="sb"&gt;



&lt;/span&gt;&lt;span class="gu"&gt;## File location&lt;/span&gt;
&lt;span class="p"&gt;
-&lt;/span&gt; Source: &lt;span class="sb"&gt;`app/Services/UserService.php`&lt;/span&gt;
&lt;span class="p"&gt;
-&lt;/span&gt; Test:   &lt;span class="sb"&gt;`tests/Unit/Services/UserServiceTest.php`



&lt;/span&gt;&lt;span class="gu"&gt;## Class under test — use constructor injection&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;&lt;br&gt;
php&lt;/p&gt;

&lt;p&gt;class UserService {&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;public function __construct(

    private readonly UserRepositoryInterface $repo

) {}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;p&gt;}&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;


## Mock pattern — Mockery (included with Pest/PHPUnit)

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;&lt;br&gt;
php&lt;/p&gt;

&lt;p&gt;it('throws exception when user not found', function () {&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// Arrange

$repo = Mockery::mock(UserRepositoryInterface::class);

$repo-&amp;gt;shouldReceive('findById')-&amp;gt;once()-&amp;gt;andReturn(null);

$service = new UserService($repo);



// Act &amp;amp; Assert

expect(fn () =&amp;gt; $service-&amp;gt;getUser('abc'))

    -&amp;gt;toThrow(UserNotFoundException::class);
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;p&gt;});&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;


## Data provider pattern (Pest datasets)

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;&lt;br&gt;
php&lt;/p&gt;

&lt;p&gt;it('validates email format', function (string $email, bool $valid) {&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;expect(validateEmail($email))-&amp;gt;toBe($valid);
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;p&gt;})-&amp;gt;with([&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;['valid@email.com', true],

['notanemail', false],

['', false],

['@nodomain.com', false],
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;p&gt;]);&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;


## What NOT to do in unit tests

- Never call $this-&amp;gt;get() or $this-&amp;gt;post() — that is feature testing

- Never use RefreshDatabase — that is feature/integration testing

- Never resolve from service container — inject directly

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;&lt;br&gt;
markdown&lt;/p&gt;


&lt;h2&gt;
  
  
  Part 4 — CLAUDE.md (Claude Project Memory)
&lt;/h2&gt;

&lt;p&gt;Place this at project root. Claude reads it on every session automatically.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;File: &lt;code&gt;CLAUDE.md&lt;/code&gt;&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight markdown"&gt;&lt;code&gt;
&lt;span class="gh"&gt;# Project: [Your Project Name]&lt;/span&gt;

&lt;span class="gh"&gt;# Claude Unit Test Instructions&lt;/span&gt;&lt;span class="sb"&gt;



&lt;/span&gt;&lt;span class="gu"&gt;## Stack&lt;/span&gt;
&lt;span class="p"&gt;
-&lt;/span&gt; Backend: NestJS + TypeScript
&lt;span class="p"&gt;
-&lt;/span&gt; Frontend: React + Vite + TypeScript
&lt;span class="p"&gt;
-&lt;/span&gt; Testing: Jest (NestJS) + Vitest (React) + Pest (Laravel) + pytest (Python)&lt;span class="sb"&gt;



&lt;/span&gt;&lt;span class="gu"&gt;## Unit Test Rules — NON-NEGOTIABLE&lt;/span&gt;&lt;span class="sb"&gt;



&lt;/span&gt;&lt;span class="gu"&gt;### When asked to generate a unit test:&lt;/span&gt;
&lt;span class="p"&gt;
1.&lt;/span&gt; NEVER generate integration or E2E tests unless explicitly asked
&lt;span class="p"&gt;
2.&lt;/span&gt; ALWAYS mock every external dependency
&lt;span class="p"&gt;
3.&lt;/span&gt; ALWAYS follow AAA (Arrange-Act-Assert) with comments
&lt;span class="p"&gt;
4.&lt;/span&gt; ALWAYS generate minimum 4 cases: happy path, null/empty, error thrown, edge case
&lt;span class="p"&gt;
5.&lt;/span&gt; NEVER use &lt;span class="sb"&gt;`any`&lt;/span&gt; type in TypeScript tests
&lt;span class="p"&gt;
6.&lt;/span&gt; NEVER leave &lt;span class="sb"&gt;`TODO`&lt;/span&gt; comments in generated tests&lt;span class="sb"&gt;



&lt;/span&gt;&lt;span class="gu"&gt;### Naming&lt;/span&gt;
&lt;span class="p"&gt;
-&lt;/span&gt; NestJS: &lt;span class="sb"&gt;`[name].service.spec.ts`&lt;/span&gt; inside same directory as source
&lt;span class="p"&gt;
-&lt;/span&gt; React: &lt;span class="sb"&gt;`[ComponentName].test.tsx`&lt;/span&gt; inside &lt;span class="sb"&gt;`__tests__/`&lt;/span&gt; or same directory
&lt;span class="p"&gt;
-&lt;/span&gt; Python: &lt;span class="sb"&gt;`test_[module].py`&lt;/span&gt; under &lt;span class="sb"&gt;`tests/unit/`&lt;/span&gt;
&lt;span class="p"&gt;
-&lt;/span&gt; Laravel: &lt;span class="sb"&gt;`[Name]Test.php`&lt;/span&gt; under &lt;span class="sb"&gt;`tests/Unit/`



&lt;/span&gt;&lt;span class="gu"&gt;### Test should describe BEHAVIOR, not implementation&lt;/span&gt;

GOOD: "should return empty array when no users match search"

BAD: "test getUserByFilter"&lt;span class="sb"&gt;



&lt;/span&gt;&lt;span class="gu"&gt;### If you are unsure of the correct mock structure:&lt;/span&gt;
&lt;span class="p"&gt;
-&lt;/span&gt; Ask what the dependency interface looks like
&lt;span class="p"&gt;
-&lt;/span&gt; Do NOT invent method names that don't exist in the source&lt;span class="sb"&gt;



&lt;/span&gt;&lt;span class="gu"&gt;### Coverage target: 80% lines, 75% branches per module&lt;/span&gt;&lt;span class="sb"&gt;



&lt;/span&gt;&lt;span class="gu"&gt;## Project Structure Reference&lt;/span&gt;

src/

  modules/&lt;span class="sb"&gt;

    users/

      users.service.ts

      users.service.spec.ts   ← unit test lives here

      users.repository.ts

      users.repository.spec.ts

&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Part 5 — MCP Servers for Unit Testing in Cursor + Claude
&lt;/h2&gt;

&lt;p&gt;MCP (Model Context Protocol) servers extend AI capabilities. For unit testing, these are the relevant ones:&lt;/p&gt;

&lt;h3&gt;
  
  
  5.1 Filesystem MCP (Built-in Cursor — use directly)
&lt;/h3&gt;

&lt;p&gt;Cursor already has filesystem access. No extra MCP needed to read source files and generate tests. The &lt;code&gt;.cursor/rules/&lt;/code&gt; system handles this.&lt;/p&gt;

&lt;h3&gt;
  
  
  5.2 Available MCP Servers for Testing Workflows
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;1. &lt;code&gt;@executeautomation/playwright-mcp-server&lt;/code&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Scope: E2E only — not relevant for unit tests&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Skip for this use case&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;2. &lt;code&gt;@modelcontextprotocol/server-filesystem&lt;/code&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Gives Claude access to project files&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Use in Claude Desktop to read source → generate tests&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Install: configured in &lt;code&gt;claude_desktop_config.json&lt;/code&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;3. Custom Testing MCP (Build This — Highest Value)&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Build a lightweight MCP server that:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Reads a source file&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Extracts function signatures + types&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Returns structured JSON to Claude&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Claude generates tests from structure, not guesswork&lt;br&gt;
&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;
&lt;span class="c1"&gt;// mcp-test-generator/src/index.ts&lt;/span&gt;

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;Server&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@modelcontextprotocol/sdk/server/index.js&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;StdioServerTransport&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@modelcontextprotocol/sdk/server/stdio.js&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nx"&gt;ts&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;typescript&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;



&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;server&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Server&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;test-generator&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;version&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;1.0.0&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;

  &lt;span class="na"&gt;capabilities&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;tools&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="p"&gt;});&lt;/span&gt;



&lt;span class="nx"&gt;server&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setRequestHandler&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;tools/call&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;

  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;params&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;extract_signatures&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;

    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;filePath&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;params&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;arguments&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;signatures&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;extractFunctionSignatures&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;filePath&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// parse AST&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;content&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[{&lt;/span&gt; &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;text&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;text&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;stringify&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;signatures&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;}]&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;

  &lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="p"&gt;});&lt;/span&gt;



&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;extractFunctionSignatures&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;filePath&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;

  &lt;span class="c1"&gt;// Use TypeScript compiler API to extract:&lt;/span&gt;

  &lt;span class="c1"&gt;// - class name&lt;/span&gt;

  &lt;span class="c1"&gt;// - method names&lt;/span&gt;

  &lt;span class="c1"&gt;// - parameter types&lt;/span&gt;

  &lt;span class="c1"&gt;// - return types&lt;/span&gt;

  &lt;span class="c1"&gt;// - injected dependencies (constructor params)&lt;/span&gt;

  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;program&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;ts&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;createProgram&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="nx"&gt;filePath&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="p"&gt;{});&lt;/span&gt;

  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;sourceFile&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;program&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getSourceFile&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;filePath&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="c1"&gt;// ... AST traversal&lt;/span&gt;

  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;className&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;methods&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;dependencies&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="p"&gt;}&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Why this matters:&lt;/strong&gt; When Claude receives typed signatures instead of raw source code, it cannot hallucinate — it generates tests from concrete types, not guesses.&lt;/p&gt;

&lt;h3&gt;
  
  
  5.3 Claude Desktop MCP Config
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="err"&gt;//&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;~/Library/Application&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;Support/Claude/claude_desktop_config.json&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;(macOS)&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="err"&gt;//&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;%APPDATA%\Claude\claude_desktop_config.json&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;(Windows)&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;

  &lt;/span&gt;&lt;span class="nl"&gt;"mcpServers"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;

    &lt;/span&gt;&lt;span class="nl"&gt;"filesystem"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;

      &lt;/span&gt;&lt;span class="nl"&gt;"command"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"npx"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;

      &lt;/span&gt;&lt;span class="nl"&gt;"args"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"-y"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"@modelcontextprotocol/server-filesystem"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"/path/to/your/project"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;

    &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;

    &lt;/span&gt;&lt;span class="nl"&gt;"test-generator"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;

      &lt;/span&gt;&lt;span class="nl"&gt;"command"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"node"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;

      &lt;/span&gt;&lt;span class="nl"&gt;"args"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"/path/to/your/mcp-test-generator/dist/index.js"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;

    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;

  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  5.4 Cursor MCP Config
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="err"&gt;//&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;.cursor/mcp.json&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;(project-level)&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;

  &lt;/span&gt;&lt;span class="nl"&gt;"mcpServers"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;

    &lt;/span&gt;&lt;span class="nl"&gt;"test-generator"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;

      &lt;/span&gt;&lt;span class="nl"&gt;"command"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"node"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;

      &lt;/span&gt;&lt;span class="nl"&gt;"args"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"./tools/mcp-test-generator/dist/index.js"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;

    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;

  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Part 6 — Anti-Hallucination Prompt Templates
&lt;/h2&gt;

&lt;p&gt;The root cause of AI hallucination in tests: AI invents method names, wrong mock structures, non-existent imports. These prompts eliminate that.&lt;/p&gt;

&lt;h3&gt;
  
  
  6.1 Cursor Cmd+K Prompt (Use This Exactly)
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;
Generate a unit &lt;span class="nb"&gt;test &lt;/span&gt;file &lt;span class="k"&gt;for &lt;/span&gt;this &lt;span class="o"&gt;[&lt;/span&gt;NestJS service / React component / Python class / Angular service / Laravel service].



Rules:

- Library: &lt;span class="o"&gt;[&lt;/span&gt;Jest / Vitest / pytest / Jest / Pest]

- Test only THIS file — no integration

- Mock ALL dependencies listed &lt;span class="k"&gt;in &lt;/span&gt;the constructor/props

- Follow AAA pattern with comments

- Minimum 4 &lt;span class="nb"&gt;test &lt;/span&gt;cases per public method

- Use ONLY methods/properties that exist &lt;span class="k"&gt;in &lt;/span&gt;this &lt;span class="nb"&gt;source &lt;/span&gt;file

- Do NOT import anything not shown &lt;span class="k"&gt;in &lt;/span&gt;the &lt;span class="nb"&gt;source&lt;/span&gt;

- Naming: &lt;span class="s2"&gt;"should [behavior] when [condition]"&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  6.2 Claude Prompt (For CLAUDE.md aware sessions)
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight markdown"&gt;&lt;code&gt;
Read [filename].

Extract:
&lt;span class="p"&gt;
1.&lt;/span&gt; Class/function name
&lt;span class="p"&gt;
2.&lt;/span&gt; All public methods with parameter types and return types
&lt;span class="p"&gt;
3.&lt;/span&gt; All constructor dependencies (for mocking)&lt;span class="sb"&gt;



&lt;/span&gt;Then generate the unit test file following CLAUDE.md rules.

Do NOT assume any method exists unless you can see it in the source.

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  6.3 Batch Test Generation Prompt
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;
&lt;span class="k"&gt;For&lt;/span&gt; &lt;span class="n"&gt;each&lt;/span&gt; &lt;span class="n"&gt;file&lt;/span&gt; &lt;span class="n"&gt;in&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;directory&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="n"&gt;generate&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="n"&gt;corresponding&lt;/span&gt; &lt;span class="mf"&gt;.&lt;/span&gt;&lt;span class="n"&gt;spec&lt;/span&gt;&lt;span class="mf"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ts&lt;/span&gt; &lt;span class="n"&gt;file&lt;/span&gt;&lt;span class="mf"&gt;.&lt;/span&gt;

&lt;span class="nc"&gt;Process&lt;/span&gt; &lt;span class="n"&gt;one&lt;/span&gt; &lt;span class="n"&gt;file&lt;/span&gt; &lt;span class="n"&gt;at&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="mf"&gt;.&lt;/span&gt;

&lt;span class="k"&gt;For&lt;/span&gt; &lt;span class="n"&gt;each&lt;/span&gt; &lt;span class="n"&gt;file&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;

  &lt;span class="mf"&gt;1.&lt;/span&gt; &lt;span class="nc"&gt;Read&lt;/span&gt; &lt;span class="n"&gt;the&lt;/span&gt; &lt;span class="n"&gt;source&lt;/span&gt;

  &lt;span class="mf"&gt;2.&lt;/span&gt; &lt;span class="k"&gt;List&lt;/span&gt; &lt;span class="n"&gt;the&lt;/span&gt; &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;methods&lt;/span&gt; &lt;span class="n"&gt;you&lt;/span&gt; &lt;span class="nf"&gt;found&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;confirm&lt;/span&gt; &lt;span class="n"&gt;before&lt;/span&gt; &lt;span class="n"&gt;generating&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

  &lt;span class="mf"&gt;3.&lt;/span&gt; &lt;span class="nc"&gt;Generate&lt;/span&gt; &lt;span class="n"&gt;the&lt;/span&gt; &lt;span class="n"&gt;test&lt;/span&gt; &lt;span class="n"&gt;file&lt;/span&gt;

  &lt;span class="mf"&gt;4.&lt;/span&gt; &lt;span class="nc"&gt;Show&lt;/span&gt; &lt;span class="n"&gt;the&lt;/span&gt; &lt;span class="n"&gt;test&lt;/span&gt; &lt;span class="n"&gt;file&lt;/span&gt; &lt;span class="n"&gt;path&lt;/span&gt;



&lt;span class="k"&gt;Do&lt;/span&gt; &lt;span class="n"&gt;not&lt;/span&gt; &lt;span class="n"&gt;proceed&lt;/span&gt; &lt;span class="n"&gt;to&lt;/span&gt; &lt;span class="n"&gt;the&lt;/span&gt; &lt;span class="n"&gt;next&lt;/span&gt; &lt;span class="n"&gt;file&lt;/span&gt; &lt;span class="n"&gt;until&lt;/span&gt; &lt;span class="n"&gt;the&lt;/span&gt; &lt;span class="n"&gt;current&lt;/span&gt; &lt;span class="n"&gt;one&lt;/span&gt; &lt;span class="n"&gt;is&lt;/span&gt; &lt;span class="n"&gt;confirmed&lt;/span&gt;&lt;span class="mf"&gt;.&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Part 7 — Project Structure Convention
&lt;/h2&gt;

&lt;p&gt;All stacks follow the same proximity principle: &lt;strong&gt;test file lives next to source file&lt;/strong&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Node.js / NestJS / Angular
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight markdown"&gt;&lt;code&gt;
src/

  modules/&lt;span class="sb"&gt;

    users/

      users.service.ts

      users.service.spec.ts        ← unit test

      users.repository.ts

      users.repository.spec.ts     ← unit test

      users.guard.ts

      users.guard.spec.ts          ← unit test

&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  React
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
src/

  components/

    UserCard/

      UserCard.tsx

      UserCard.test.tsx            ← unit test

      UserCard.stories.tsx         ← storybook (optional)

  hooks/

    useUserData.ts

    useUserData.test.ts            ← unit test

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Python
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
app/

  services/

    user_service.py

tests/

  unit/

    services/

      test_user_service.py        ← mirrors app/ structure

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Laravel
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
app/

  Services/

    UserService.php

tests/

  Unit/

    Services/

      UserServiceTest.php         ← mirrors app/ structure

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Part 8 — CI Enforcement
&lt;/h2&gt;

&lt;p&gt;All of this means nothing without enforcement. The pipeline is the final gate.&lt;/p&gt;

&lt;h3&gt;
  
  
  GitHub Actions — Multi-stack parallel
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;
&lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Unit Tests&lt;/span&gt;



&lt;span class="na"&gt;on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;push&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;pull_request&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;



&lt;span class="na"&gt;jobs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;

  &lt;span class="na"&gt;nestjs-unit&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;

    &lt;span class="na"&gt;runs-on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;ubuntu-latest&lt;/span&gt;

    &lt;span class="na"&gt;steps&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;

      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;actions/checkout@v4&lt;/span&gt;

      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;actions/setup-node@v4&lt;/span&gt;

        &lt;span class="na"&gt;with&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;{&lt;/span&gt; &lt;span class="nv"&gt;node-version&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;20'&lt;/span&gt; &lt;span class="pi"&gt;}&lt;/span&gt;

      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;npm ci&lt;/span&gt;

      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;npm run test:unit -- --coverage --coverageThreshold='{"global":{"lines":80}}'&lt;/span&gt;



  &lt;span class="na"&gt;react-unit&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;

    &lt;span class="na"&gt;runs-on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;ubuntu-latest&lt;/span&gt;

    &lt;span class="na"&gt;steps&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;

      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;actions/checkout@v4&lt;/span&gt;

      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;actions/setup-node@v4&lt;/span&gt;

        &lt;span class="na"&gt;with&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;{&lt;/span&gt; &lt;span class="nv"&gt;node-version&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;20'&lt;/span&gt; &lt;span class="pi"&gt;}&lt;/span&gt;

      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;npm ci&lt;/span&gt;

      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;npx vitest run --coverage&lt;/span&gt;



  &lt;span class="na"&gt;python-unit&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;

    &lt;span class="na"&gt;runs-on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;ubuntu-latest&lt;/span&gt;

    &lt;span class="na"&gt;steps&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;

      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;actions/checkout@v4&lt;/span&gt;

      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;actions/setup-python@v5&lt;/span&gt;

        &lt;span class="na"&gt;with&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;{&lt;/span&gt; &lt;span class="nv"&gt;python-version&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;3.12'&lt;/span&gt; &lt;span class="pi"&gt;}&lt;/span&gt;

      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;pip install -r requirements-dev.txt&lt;/span&gt;

      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;pytest tests/unit/ --cov=app --cov-fail-under=80&lt;/span&gt;



  &lt;span class="na"&gt;laravel-unit&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;

    &lt;span class="na"&gt;runs-on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;ubuntu-latest&lt;/span&gt;

    &lt;span class="na"&gt;steps&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;

      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;actions/checkout@v4&lt;/span&gt;

      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;shivammathur/setup-php@v2&lt;/span&gt;

        &lt;span class="na"&gt;with&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;{&lt;/span&gt; &lt;span class="nv"&gt;php-version&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;8.3'&lt;/span&gt; &lt;span class="pi"&gt;}&lt;/span&gt;

      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;composer install&lt;/span&gt;

      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;./vendor/bin/pest --coverage --min=80&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Pre-commit Hook (Husky — Node stacks)
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="err"&gt;//&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;package.json&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;

  &lt;/span&gt;&lt;span class="nl"&gt;"lint-staged"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;

    &lt;/span&gt;&lt;span class="nl"&gt;"src/**/*.service.ts"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"jest --findRelatedTests --passWithNoTests"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;

    &lt;/span&gt;&lt;span class="nl"&gt;"src/**/*.tsx"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"vitest related --run"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;

  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Part 9 — Quick Start Checklist
&lt;/h2&gt;

&lt;h3&gt;
  
  
  New Project
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
□ Install test library (one per stack — see Part 1)

□ Configure jest.config.ts / vitest.config.ts / pytest.ini / pest.php

□ Create .cursor/rules/ directory with all rule files from Part 3

□ Create CLAUDE.md at project root from Part 4

□ Add coverage thresholds to config

□ Add pre-commit hooks (Husky for Node, pre-commit for Python)

□ Add CI workflow from Part 8

□ Create test factory files (one per major entity)

□ Write first failing test → implement → green → commit

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Existing Project
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
□ Add test library without touching existing code

□ Add .cursor/rules/ + CLAUDE.md

□ Run coverage on existing code → document current baseline

□ Pick 3 critical services → generate tests → set as new baseline

□ Add CI with threshold = current baseline (not ideal — current)

□ Raise threshold by 5% per sprint

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Appendix — Install Commands Per Stack
&lt;/h2&gt;

&lt;h3&gt;
  
  
  NestJS
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;
npm &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;--save-dev&lt;/span&gt; jest ts-jest @types/jest @nestjs/testing jest-mock-extended @golevelup/ts-jest

npx ts-jest config:init

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  React (Vite)
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;
npm &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;--save-dev&lt;/span&gt; vitest @vitest/coverage-v8 @testing-library/react @testing-library/user-event @testing-library/jest-dom jsdom

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Python
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;
pip &lt;span class="nb"&gt;install &lt;/span&gt;pytest pytest-cov pytest-mock pytest-asyncio factory-boy

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Angular
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;
ng add @angular-builders/jest

npm &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;--save-dev&lt;/span&gt; jest jest-preset-angular @types/jest

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Laravel
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;
composer require pestphp/pest pestphp/pest-plugin-laravel &lt;span class="nt"&gt;--dev&lt;/span&gt;

./vendor/bin/pest &lt;span class="nt"&gt;--init&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;p&gt;&lt;em&gt;Last updated: 2025 — verify library major versions before adopting&lt;/em&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>llm</category>
      <category>testing</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>Unit Test AI Guide — Zero Hallucination, Cross-Stack Standard</title>
      <dc:creator>Bhaumik</dc:creator>
      <pubDate>Fri, 19 Jun 2026 11:46:34 +0000</pubDate>
      <link>https://dev.to/bhaumik-viitor/unit-test-ai-guide-zero-hallucination-cross-stack-standard-p18</link>
      <guid>https://dev.to/bhaumik-viitor/unit-test-ai-guide-zero-hallucination-cross-stack-standard-p18</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Focus:&lt;/strong&gt; Unit Tests ONLY — no integration, no E2E  &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Stacks:&lt;/strong&gt; Node.js (NestJS/Express) · React.js · Python · Angular · Laravel  &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Goal:&lt;/strong&gt; AI generates unit tests consistently, deterministically, without hallucination  &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;IDE:&lt;/strong&gt; Cursor (Primary) + Claude (Secondary)&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  Part 1 — Best Single Library Per Stack (Final Decision)
&lt;/h2&gt;

&lt;p&gt;Do not mix libraries. Pick one per stack, configure it fully, never deviate.&lt;/p&gt;

&lt;p&gt;| Stack | Library | Why This One |&lt;/p&gt;

&lt;p&gt;|---|---|---|&lt;/p&gt;

&lt;p&gt;| &lt;strong&gt;Node.js / NestJS / Express&lt;/strong&gt; | &lt;code&gt;Jest&lt;/code&gt; | Native DI mocking, &lt;code&gt;@nestjs/testing&lt;/code&gt; built around it, widest ecosystem |&lt;/p&gt;

&lt;p&gt;| &lt;strong&gt;React.js&lt;/strong&gt; | &lt;code&gt;Vitest&lt;/code&gt; + &lt;code&gt;@testing-library/react&lt;/code&gt; | Native Vite/ESM support, Jest-compatible API, 3–10x faster |&lt;/p&gt;

&lt;p&gt;| &lt;strong&gt;Python&lt;/strong&gt; | &lt;code&gt;pytest&lt;/code&gt; | De facto standard, fixture system eliminates boilerplate, best plugin ecosystem |&lt;/p&gt;

&lt;p&gt;| &lt;strong&gt;Angular&lt;/strong&gt; | &lt;code&gt;Jest&lt;/code&gt; (replace Karma) | Karma is deprecated in Angular 17+; Jest is the official migration target |&lt;/p&gt;

&lt;p&gt;| &lt;strong&gt;Laravel&lt;/strong&gt; | &lt;code&gt;Pest&lt;/code&gt; | Modern syntax, built on PHPUnit, higher signal-to-noise ratio |&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Rule:&lt;/strong&gt; If someone suggests a second library for the same stack, reject it. One library per stack, configured once, followed always.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  Part 2 — IDE: Cursor (Only Choice for This Goal)
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Why Cursor and Not VS Code / WebStorm
&lt;/h3&gt;

&lt;p&gt;| Capability | Cursor | VS Code + Copilot | WebStorm |&lt;/p&gt;

&lt;p&gt;|---|---|---|---|&lt;/p&gt;

&lt;p&gt;| Project-level AI rules | ✅ &lt;code&gt;.cursor/rules/&lt;/code&gt; | ❌ | ❌ |&lt;/p&gt;

&lt;p&gt;| Codebase-aware context | ✅ &lt;code&gt;@codebase&lt;/code&gt; | Partial | Partial |&lt;/p&gt;

&lt;p&gt;| Run terminal + read output | ✅ Composer | ❌ | ❌ |&lt;/p&gt;

&lt;p&gt;| Multi-file generation | ✅ Agent mode | Limited | ❌ |&lt;/p&gt;

&lt;p&gt;| Custom instructions per filetype | ✅ | ❌ | ❌ |&lt;/p&gt;

&lt;p&gt;| MCP server integration | ✅ | ❌ | ❌ |&lt;/p&gt;

&lt;p&gt;Cursor's &lt;code&gt;.cursor/rules/&lt;/code&gt; system is the &lt;strong&gt;only IDE-native mechanism&lt;/strong&gt; that injects persistent, project-scoped instructions into every AI interaction — this is what prevents hallucination at the source.&lt;/p&gt;

&lt;h3&gt;
  
  
  Cursor Setup for This Project
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

project-root/


├── .cursor/


│   └── rules/


│       ├── unit-test-global.mdc       ← applies to all files


│       ├── unit-test-nestjs.mdc       ← applies to *.service.ts, *.guard.ts


│       ├── unit-test-react.mdc        ← applies to *.tsx, *.component.tsx


│       ├── unit-test-python.mdc       ← applies to *.py


│       ├── unit-test-angular.mdc      ← applies to *.component.ts, *.service.ts


│       └── unit-test-laravel.mdc      ← applies to *Service.php, *Model.php


├── CLAUDE.md                          ← Claude project memory file


└── ...


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Part 3 — Cursor Rules Files (Anti-Hallucination Core)
&lt;/h2&gt;

&lt;p&gt;These files are injected into every AI prompt automatically when working on matching files.&lt;/p&gt;

&lt;h3&gt;
  
  
  3.1 Global Unit Test Rule
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;File: &lt;code&gt;.cursor/rules/unit-test-global.mdc&lt;/code&gt;&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight markdown"&gt;&lt;code&gt;&lt;span class="p"&gt;

---

&lt;/span&gt;
description: Global unit test rules — applies to all files in this project&lt;span class="sb"&gt;


&lt;/span&gt;globs: ["&lt;span class="gs"&gt;**/*.spec.ts", "**&lt;/span&gt;/&lt;span class="ge"&gt;*.test.ts", "**/*&lt;/span&gt;.spec.tsx", "&lt;span class="gs"&gt;**/*_test.py", "**&lt;/span&gt;/Test&lt;span class="err"&gt;*&lt;/span&gt;.php"]&lt;span class="sb"&gt;


&lt;/span&gt;alwaysApply: true&lt;span class="sb"&gt;


&lt;/span&gt;&lt;span class="p"&gt;---




&lt;/span&gt;
&lt;span class="gh"&gt;# Unit Test Contract — MUST FOLLOW, NO EXCEPTIONS&lt;/span&gt;&lt;span class="sb"&gt;





&lt;/span&gt;&lt;span class="gu"&gt;## What is a unit test here&lt;/span&gt;&lt;span class="sb"&gt;


&lt;/span&gt;&lt;span class="p"&gt;-&lt;/span&gt; Tests ONE class or function in complete isolation&lt;span class="sb"&gt;


&lt;/span&gt;&lt;span class="p"&gt;-&lt;/span&gt; ALL external dependencies are mocked — no real DB, no real HTTP, no real file system&lt;span class="sb"&gt;


&lt;/span&gt;&lt;span class="p"&gt;-&lt;/span&gt; Each test runs independently — no shared mutable state between tests&lt;span class="sb"&gt;


&lt;/span&gt;&lt;span class="p"&gt;-&lt;/span&gt; Runs in &amp;lt; 100ms&lt;span class="sb"&gt;





&lt;/span&gt;&lt;span class="gu"&gt;## Structure: AAA — Always, Without Exception&lt;/span&gt;&lt;span class="sb"&gt;


&lt;/span&gt;Every test MUST have these three sections, with comments:&lt;span class="sb"&gt;


&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;// Arrange — set up inputs, mocks, expected values&lt;/p&gt;

&lt;p&gt;// Act — call the single function/method under test&lt;/p&gt;

&lt;p&gt;// Assert — verify exactly one outcome&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;




## Naming Convention — Mandatory


- File: `[module-name].spec.ts` or `[module-name].unit.spec.ts`


- Describe block: exact class or function name


- It/test block: "should [expected behavior] when [specific condition]"


  GOOD: "should throw NotFoundException when user does not exist"


  BAD:  "user not found", "test 1", "works correctly"





## What to test per function — minimum coverage


1. Happy path — valid input → expected output


2. Null/undefined input — how does it fail safely


3. Empty input — empty string, empty array, zero


4. Error path — when dependency throws, what happens


5. Boundary — max length, negative numbers, boolean edge





## What NOT to include in unit tests


- Database queries (mock the repository)


- HTTP calls (mock the service/axios/fetch)


- File system operations (mock fs)


- Timer behavior (use jest.useFakeTimers)


- Random values (mock Math.random or faker with fixed seed)





## AI Instruction


When asked to generate a unit test:


1. READ the function signature and types first


2. IDENTIFY all dependencies (constructor args, imported modules)


3. MOCK every dependency — never use real implementations


4. Generate minimum 4 test cases per method (happy, null, error, edge)


5. NEVER import from test doubles or assume what isn't in the source file


6. If you are unsure of a type — ASK, do not assume


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h3&gt;
  
  
  3.2 NestJS Rule
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;File: &lt;code&gt;.cursor/rules/unit-test-nestjs.mdc&lt;/code&gt;&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight markdown"&gt;&lt;code&gt;&lt;span class="p"&gt;

---

&lt;/span&gt;
description: NestJS unit test rules&lt;span class="sb"&gt;


&lt;/span&gt;globs: ["src/&lt;span class="gs"&gt;**/*.service.ts", "src/**&lt;/span&gt;/&lt;span class="ge"&gt;*.guard.ts", "src/**/*&lt;/span&gt;.interceptor.ts", "src/&lt;span class="ge"&gt;**&lt;/span&gt;/&lt;span class="err"&gt;*&lt;/span&gt;.pipe.ts"]&lt;span class="sb"&gt;


&lt;/span&gt;&lt;span class="p"&gt;---




&lt;/span&gt;
&lt;span class="gh"&gt;# NestJS Unit Test Rules&lt;/span&gt;&lt;span class="sb"&gt;





&lt;/span&gt;&lt;span class="gu"&gt;## Library: Jest + @nestjs/testing + jest-mock-extended&lt;/span&gt;&lt;span class="sb"&gt;





&lt;/span&gt;&lt;span class="gu"&gt;## Always use Test.createTestingModule&lt;/span&gt;&lt;span class="sb"&gt;


&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;&lt;br&gt;
typescript&lt;/p&gt;

&lt;p&gt;const module = await Test.createTestingModule({&lt;/p&gt;

&lt;p&gt;providers: [&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;SubjectService,


{ provide: DependencyService, useValue: mockDependency }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;p&gt;]&lt;/p&gt;

&lt;p&gt;}).compile();&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;




## Mock Pattern — jest-mock-extended


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;&lt;br&gt;
typescript&lt;/p&gt;

&lt;p&gt;import { createMock } from '@golevelup/ts-jest';&lt;/p&gt;

&lt;p&gt;// OR&lt;/p&gt;

&lt;p&gt;import { mock } from 'jest-mock-extended';&lt;/p&gt;

&lt;p&gt;const mockUserRepo = mock();&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;




## Never


- Never use `new SubjectService()` directly — always use TestingModule


- Never let `useValue` contain real implementations


- Never test more than one service per describe block





## Repository Mock Template


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;&lt;br&gt;
typescript&lt;/p&gt;

&lt;p&gt;const mockRepo = {&lt;/p&gt;

&lt;p&gt;findOne: jest.fn(),&lt;/p&gt;

&lt;p&gt;save: jest.fn(),&lt;/p&gt;

&lt;p&gt;delete: jest.fn(),&lt;/p&gt;

&lt;p&gt;findAll: jest.fn(),&lt;/p&gt;

&lt;p&gt;update: jest.fn(),&lt;/p&gt;

&lt;p&gt;};&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;




## Required imports for every NestJS spec file


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;&lt;br&gt;
typescript&lt;/p&gt;

&lt;p&gt;import { Test, TestingModule } from '@nestjs/testing';&lt;/p&gt;

&lt;p&gt;import { NotFoundException, BadRequestException } from '@nestjs/common';&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;&lt;br&gt;
markdown&lt;/p&gt;


&lt;h3&gt;
  
  
  3.3 React Rule
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;File: &lt;code&gt;.cursor/rules/unit-test-react.mdc&lt;/code&gt;&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight markdown"&gt;&lt;code&gt;&lt;span class="p"&gt;

---

&lt;/span&gt;
description: React unit test rules&lt;span class="sb"&gt;


&lt;/span&gt;globs: ["src/&lt;span class="gs"&gt;**/*.tsx", "src/**&lt;/span&gt;/&lt;span class="ge"&gt;*.component.tsx", "src/hooks/**/*&lt;/span&gt;.ts"]&lt;span class="sb"&gt;


&lt;/span&gt;&lt;span class="p"&gt;---




&lt;/span&gt;
&lt;span class="gh"&gt;# React Unit Test Rules&lt;/span&gt;&lt;span class="sb"&gt;





&lt;/span&gt;&lt;span class="gu"&gt;## Library: Vitest + @testing-library/react + @testing-library/user-event&lt;/span&gt;&lt;span class="sb"&gt;





&lt;/span&gt;&lt;span class="gu"&gt;## Required setup in vitest.config.ts&lt;/span&gt;&lt;span class="sb"&gt;


&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;&lt;br&gt;
typescript&lt;/p&gt;

&lt;p&gt;export default defineConfig({&lt;/p&gt;

&lt;p&gt;test: {&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;environment: 'jsdom',


globals: true,


setupFiles: ['./src/test/setup.ts']
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;p&gt;}&lt;/p&gt;

&lt;p&gt;})&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;




## setup.ts


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;&lt;br&gt;
typescript&lt;/p&gt;

&lt;p&gt;import '@testing-library/jest-dom';&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;




## Component test structure


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;&lt;br&gt;
typescript&lt;/p&gt;

&lt;p&gt;import { render, screen } from '@testing-library/react';&lt;/p&gt;

&lt;p&gt;import userEvent from '@testing-library/user-event';&lt;/p&gt;

&lt;p&gt;import { vi } from 'vitest';&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;




## Mocking rules for React


- Mock ALL hooks that call APIs: `vi.mock('../hooks/useUsers')`


- Mock ALL context providers — wrap with test-specific providers


- Mock router: use `MemoryRouter` from react-router-dom


- NEVER mock internal state (useState) — test behavior, not implementation





## Query priority (RTL best practice — mandatory)


1. getByRole — prefer always


2. getByLabelText — for forms


3. getByText — for content


4. getByTestId — LAST RESORT only, requires data-testid attribute





## User event — always use userEvent, never fireEvent


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;&lt;br&gt;
typescript&lt;/p&gt;

&lt;p&gt;const user = userEvent.setup();&lt;/p&gt;

&lt;p&gt;await user.click(button);&lt;/p&gt;

&lt;p&gt;await user.type(input, 'value');&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;




## Custom hook testing


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;&lt;br&gt;
typescript&lt;/p&gt;

&lt;p&gt;import { renderHook, act } from '@testing-library/react';&lt;/p&gt;

&lt;p&gt;const { result } = renderHook(() =&amp;gt; useMyHook());&lt;/p&gt;

&lt;p&gt;act(() =&amp;gt; result.current.doSomething());&lt;/p&gt;

&lt;p&gt;expect(result.current.value).toBe('expected');&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;&lt;br&gt;
typescript&lt;/p&gt;


&lt;h3&gt;
  
  
  3.4 Python Rule
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;File: &lt;code&gt;.cursor/rules/unit-test-python.mdc&lt;/code&gt;&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight markdown"&gt;&lt;code&gt;&lt;span class="p"&gt;

---

&lt;/span&gt;
description: Python unit test rules&lt;span class="sb"&gt;


&lt;/span&gt;globs: ["&lt;span class="gs"&gt;**/*.py", "!**&lt;/span&gt;/&lt;span class="ge"&gt;*migrations*&lt;/span&gt;"]&lt;span class="sb"&gt;


&lt;/span&gt;&lt;span class="p"&gt;---




&lt;/span&gt;
&lt;span class="gh"&gt;# Python Unit Test Rules&lt;/span&gt;&lt;span class="sb"&gt;





&lt;/span&gt;&lt;span class="gu"&gt;## Library: pytest + pytest-mock + factory-boy&lt;/span&gt;&lt;span class="sb"&gt;





&lt;/span&gt;&lt;span class="gu"&gt;## File naming&lt;/span&gt;&lt;span class="sb"&gt;


&lt;/span&gt;&lt;span class="p"&gt;-&lt;/span&gt; Source: &lt;span class="sb"&gt;`app/services/user_service.py`


&lt;/span&gt;&lt;span class="p"&gt;-&lt;/span&gt; Test:   &lt;span class="sb"&gt;`tests/unit/test_user_service.py`


&lt;/span&gt;&lt;span class="p"&gt;-&lt;/span&gt; ALWAYS mirror the source directory structure under tests/unit/&lt;span class="sb"&gt;





&lt;/span&gt;&lt;span class="gu"&gt;## Class under test — always use dependency injection&lt;/span&gt;&lt;span class="sb"&gt;


&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;&lt;br&gt;
python&lt;/p&gt;
&lt;h1&gt;
  
  
  GOOD — injectable dependency
&lt;/h1&gt;

&lt;p&gt;class UserService:&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;def __init__(self, repo: UserRepository):


    self.repo = repo
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;h1&gt;
  
  
  BAD — untestable
&lt;/h1&gt;

&lt;p&gt;class UserService:&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;def __init__(self):


    self.repo = UserRepository()  # can't mock this
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;




## Mock pattern — pytest-mock (mocker fixture)


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;p&gt;&lt;br&gt;
python&lt;/p&gt;

&lt;p&gt;def test_raises_when_user_not_found(mocker):&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;mock_repo = mocker.Mock()


mock_repo.find_by_id.return_value = None


service = UserService(mock_repo)


with pytest.raises(UserNotFoundException):


    service.get_user("missing-id")
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;




## Async tests — pytest-asyncio


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;p&gt;&lt;br&gt;
python&lt;/p&gt;

&lt;p&gt;import pytest&lt;/p&gt;

&lt;p&gt;@pytest.mark.asyncio&lt;/p&gt;

&lt;p&gt;async def test_async_service(mocker):&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;mock_repo = mocker.AsyncMock()


...
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;




## Fixture pattern — for shared setup


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;p&gt;&lt;br&gt;
python&lt;/p&gt;

&lt;p&gt;@pytest.fixture&lt;/p&gt;

&lt;p&gt;def user_service(mocker):&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;repo = mocker.Mock()


return UserService(repo), repo
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;p&gt;def test_get_user_happy_path(user_service):&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;service, repo = user_service


repo.find_by_id.return_value = User(id="1", email="a@b.com")


result = service.get_user("1")


assert result.email == "a@b.com"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;




## Naming


- File: `test_[module_name].py`


- Function: `test_[expected_behavior]_when_[condition]`


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;p&gt;&lt;br&gt;
markdown&lt;/p&gt;


&lt;h3&gt;
  
  
  3.5 Angular Rule
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;File: &lt;code&gt;.cursor/rules/unit-test-angular.mdc&lt;/code&gt;&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight markdown"&gt;&lt;code&gt;&lt;span class="p"&gt;

---

&lt;/span&gt;
description: Angular unit test rules&lt;span class="sb"&gt;


&lt;/span&gt;globs: ["src/app/&lt;span class="gs"&gt;**/*.component.ts", "src/app/**&lt;/span&gt;/&lt;span class="ge"&gt;*.service.ts", "src/app/**/*&lt;/span&gt;.pipe.ts", "src/app/&lt;span class="ge"&gt;**&lt;/span&gt;/&lt;span class="err"&gt;*&lt;/span&gt;.guard.ts"]&lt;span class="sb"&gt;


&lt;/span&gt;&lt;span class="p"&gt;---




&lt;/span&gt;
&lt;span class="gh"&gt;# Angular Unit Test Rules&lt;/span&gt;&lt;span class="sb"&gt;





&lt;/span&gt;&lt;span class="gu"&gt;## Library: Jest (NOT Karma — Karma is deprecated Angular 17+)&lt;/span&gt;&lt;span class="sb"&gt;





&lt;/span&gt;&lt;span class="gu"&gt;## Migration from Karma to Jest (one-time)&lt;/span&gt;&lt;span class="sb"&gt;


&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;&lt;br&gt;
bash&lt;/p&gt;

&lt;p&gt;ng add @angular-builders/jest&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;




## TestBed configuration — always minimal


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;&lt;br&gt;
typescript&lt;/p&gt;

&lt;p&gt;await TestBed.configureTestingModule({&lt;/p&gt;

&lt;p&gt;imports: [ComponentUnderTest],  // standalone components&lt;/p&gt;

&lt;p&gt;providers: [&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{ provide: UserService, useValue: mockUserService }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;p&gt;]&lt;/p&gt;

&lt;p&gt;}).compileComponents();&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;




## Service mock pattern


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;&lt;br&gt;
typescript&lt;/p&gt;

&lt;p&gt;const mockUserService = {&lt;/p&gt;

&lt;p&gt;getUser: jest.fn(),&lt;/p&gt;

&lt;p&gt;createUser: jest.fn(),&lt;/p&gt;

&lt;p&gt;};&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;




## Component test — check DOM behavior, not internal state


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;&lt;br&gt;
typescript&lt;/p&gt;

&lt;p&gt;fixture.detectChanges(); // trigger ngOnInit&lt;/p&gt;

&lt;p&gt;const button = fixture.debugElement.query(By.css('[data-testid="submit"]'));&lt;/p&gt;

&lt;p&gt;button.nativeElement.click();&lt;/p&gt;

&lt;p&gt;fixture.detectChanges();&lt;/p&gt;

&lt;p&gt;expect(fixture.debugElement.query(By.css('.error-msg'))).toBeTruthy();&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;




## Pipe test — pure function, no TestBed needed


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;&lt;br&gt;
typescript&lt;/p&gt;

&lt;p&gt;it('should transform date correctly', () =&amp;gt; {&lt;/p&gt;

&lt;p&gt;const pipe = new DateFormatPipe();&lt;/p&gt;

&lt;p&gt;expect(pipe.transform(new Date('2024-01-01'))).toBe('Jan 1, 2024');&lt;/p&gt;

&lt;p&gt;});&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;




## Guard/resolver test — inject and call directly


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;&lt;br&gt;
typescript&lt;/p&gt;

&lt;p&gt;const guard = TestBed.inject(AuthGuard);&lt;/p&gt;

&lt;p&gt;const result = await guard.canActivate(mockRoute, mockState);&lt;/p&gt;

&lt;p&gt;expect(result).toBe(false);&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;&lt;br&gt;
python&lt;/p&gt;


&lt;h3&gt;
  
  
  3.6 Laravel Rule
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;File: &lt;code&gt;.cursor/rules/unit-test-laravel.mdc&lt;/code&gt;&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight markdown"&gt;&lt;code&gt;&lt;span class="p"&gt;

---

&lt;/span&gt;
description: Laravel unit test rules&lt;span class="sb"&gt;


&lt;/span&gt;globs: ["app/Services/&lt;span class="gs"&gt;**/*.php", "app/Models/**&lt;/span&gt;/&lt;span class="ge"&gt;*.php", "app/Http/Requests/**/*&lt;/span&gt;.php", "app/Actions/&lt;span class="ge"&gt;**&lt;/span&gt;/&lt;span class="err"&gt;*&lt;/span&gt;.php"]&lt;span class="sb"&gt;


&lt;/span&gt;&lt;span class="p"&gt;---




&lt;/span&gt;
&lt;span class="gh"&gt;# Laravel Unit Test Rules&lt;/span&gt;&lt;span class="sb"&gt;





&lt;/span&gt;&lt;span class="gu"&gt;## Library: Pest (NOT PHPUnit directly — Pest wraps it with better syntax)&lt;/span&gt;&lt;span class="sb"&gt;





&lt;/span&gt;&lt;span class="gu"&gt;## File location&lt;/span&gt;&lt;span class="sb"&gt;


&lt;/span&gt;&lt;span class="p"&gt;-&lt;/span&gt; Source: &lt;span class="sb"&gt;`app/Services/UserService.php`


&lt;/span&gt;&lt;span class="p"&gt;-&lt;/span&gt; Test:   &lt;span class="sb"&gt;`tests/Unit/Services/UserServiceTest.php`





&lt;/span&gt;&lt;span class="gu"&gt;## Class under test — use constructor injection&lt;/span&gt;&lt;span class="sb"&gt;


&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;&lt;br&gt;
php&lt;/p&gt;

&lt;p&gt;class UserService {&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;public function __construct(


    private readonly UserRepositoryInterface $repo


) {}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;p&gt;}&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;




## Mock pattern — Mockery (included with Pest/PHPUnit)


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;&lt;br&gt;
php&lt;/p&gt;

&lt;p&gt;it('throws exception when user not found', function () {&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// Arrange


$repo = Mockery::mock(UserRepositoryInterface::class);


$repo-&amp;gt;shouldReceive('findById')-&amp;gt;once()-&amp;gt;andReturn(null);


$service = new UserService($repo);





// Act &amp;amp; Assert


expect(fn () =&amp;gt; $service-&amp;gt;getUser('abc'))


    -&amp;gt;toThrow(UserNotFoundException::class);
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;p&gt;});&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;




## Data provider pattern (Pest datasets)


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;&lt;br&gt;
php&lt;/p&gt;

&lt;p&gt;it('validates email format', function (string $email, bool $valid) {&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;expect(validateEmail($email))-&amp;gt;toBe($valid);
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;p&gt;})-&amp;gt;with([&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;['valid@email.com', true],


['notanemail', false],


['', false],


['@nodomain.com', false],
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;p&gt;]);&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;




## What NOT to do in unit tests


- Never call $this-&amp;gt;get() or $this-&amp;gt;post() — that is feature testing


- Never use RefreshDatabase — that is feature/integration testing


- Never resolve from service container — inject directly


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;&lt;br&gt;
markdown&lt;/p&gt;


&lt;h2&gt;
  
  
  Part 4 — CLAUDE.md (Claude Project Memory)
&lt;/h2&gt;

&lt;p&gt;Place this at project root. Claude reads it on every session automatically.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;File: &lt;code&gt;CLAUDE.md&lt;/code&gt;&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight markdown"&gt;&lt;code&gt;

&lt;span class="gh"&gt;# Project: [Your Project Name]&lt;/span&gt;&lt;span class="sb"&gt;


&lt;/span&gt;&lt;span class="gh"&gt;# Claude Unit Test Instructions&lt;/span&gt;&lt;span class="sb"&gt;





&lt;/span&gt;&lt;span class="gu"&gt;## Stack&lt;/span&gt;&lt;span class="sb"&gt;


&lt;/span&gt;&lt;span class="p"&gt;-&lt;/span&gt; Backend: NestJS + TypeScript&lt;span class="sb"&gt;


&lt;/span&gt;&lt;span class="p"&gt;-&lt;/span&gt; Frontend: React + Vite + TypeScript&lt;span class="sb"&gt;


&lt;/span&gt;&lt;span class="p"&gt;-&lt;/span&gt; Testing: Jest (NestJS) + Vitest (React) + Pest (Laravel) + pytest (Python)&lt;span class="sb"&gt;





&lt;/span&gt;&lt;span class="gu"&gt;## Unit Test Rules — NON-NEGOTIABLE&lt;/span&gt;&lt;span class="sb"&gt;





&lt;/span&gt;&lt;span class="gu"&gt;### When asked to generate a unit test:&lt;/span&gt;&lt;span class="sb"&gt;


&lt;/span&gt;&lt;span class="p"&gt;1.&lt;/span&gt; NEVER generate integration or E2E tests unless explicitly asked&lt;span class="sb"&gt;


&lt;/span&gt;&lt;span class="p"&gt;2.&lt;/span&gt; ALWAYS mock every external dependency&lt;span class="sb"&gt;


&lt;/span&gt;&lt;span class="p"&gt;3.&lt;/span&gt; ALWAYS follow AAA (Arrange-Act-Assert) with comments&lt;span class="sb"&gt;


&lt;/span&gt;&lt;span class="p"&gt;4.&lt;/span&gt; ALWAYS generate minimum 4 cases: happy path, null/empty, error thrown, edge case&lt;span class="sb"&gt;


&lt;/span&gt;&lt;span class="p"&gt;5.&lt;/span&gt; NEVER use &lt;span class="sb"&gt;`any`&lt;/span&gt; type in TypeScript tests&lt;span class="sb"&gt;


&lt;/span&gt;&lt;span class="p"&gt;6.&lt;/span&gt; NEVER leave &lt;span class="sb"&gt;`TODO`&lt;/span&gt; comments in generated tests&lt;span class="sb"&gt;





&lt;/span&gt;&lt;span class="gu"&gt;### Naming&lt;/span&gt;&lt;span class="sb"&gt;


&lt;/span&gt;&lt;span class="p"&gt;-&lt;/span&gt; NestJS: &lt;span class="sb"&gt;`[name].service.spec.ts`&lt;/span&gt; inside same directory as source&lt;span class="sb"&gt;


&lt;/span&gt;&lt;span class="p"&gt;-&lt;/span&gt; React: &lt;span class="sb"&gt;`[ComponentName].test.tsx`&lt;/span&gt; inside &lt;span class="sb"&gt;`__tests__/`&lt;/span&gt; or same directory&lt;span class="sb"&gt;


&lt;/span&gt;&lt;span class="p"&gt;-&lt;/span&gt; Python: &lt;span class="sb"&gt;`test_[module].py`&lt;/span&gt; under &lt;span class="sb"&gt;`tests/unit/`


&lt;/span&gt;&lt;span class="p"&gt;-&lt;/span&gt; Laravel: &lt;span class="sb"&gt;`[Name]Test.php`&lt;/span&gt; under &lt;span class="sb"&gt;`tests/Unit/`





&lt;/span&gt;&lt;span class="gu"&gt;### Test should describe BEHAVIOR, not implementation&lt;/span&gt;&lt;span class="sb"&gt;


&lt;/span&gt;GOOD: "should return empty array when no users match search"&lt;span class="sb"&gt;


&lt;/span&gt;BAD: "test getUserByFilter"&lt;span class="sb"&gt;





&lt;/span&gt;&lt;span class="gu"&gt;### If you are unsure of the correct mock structure:&lt;/span&gt;&lt;span class="sb"&gt;


&lt;/span&gt;&lt;span class="p"&gt;-&lt;/span&gt; Ask what the dependency interface looks like&lt;span class="sb"&gt;


&lt;/span&gt;&lt;span class="p"&gt;-&lt;/span&gt; Do NOT invent method names that don't exist in the source&lt;span class="sb"&gt;





&lt;/span&gt;&lt;span class="gu"&gt;### Coverage target: 80% lines, 75% branches per module&lt;/span&gt;&lt;span class="sb"&gt;





&lt;/span&gt;&lt;span class="gu"&gt;## Project Structure Reference&lt;/span&gt;&lt;span class="sb"&gt;


&lt;/span&gt;src/&lt;span class="sb"&gt;


&lt;/span&gt;  modules/&lt;span class="sb"&gt;


    users/


      users.service.ts


      users.service.spec.ts   ← unit test lives here


      users.repository.ts


      users.repository.spec.ts


&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Part 5 — MCP Servers for Unit Testing in Cursor + Claude
&lt;/h2&gt;

&lt;p&gt;MCP (Model Context Protocol) servers extend AI capabilities. For unit testing, these are the relevant ones:&lt;/p&gt;

&lt;h3&gt;
  
  
  5.1 Filesystem MCP (Built-in Cursor — use directly)
&lt;/h3&gt;

&lt;p&gt;Cursor already has filesystem access. No extra MCP needed to read source files and generate tests. The &lt;code&gt;.cursor/rules/&lt;/code&gt; system handles this.&lt;/p&gt;

&lt;h3&gt;
  
  
  5.2 Available MCP Servers for Testing Workflows
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;1. &lt;code&gt;@executeautomation/playwright-mcp-server&lt;/code&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Scope: E2E only — not relevant for unit tests&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Skip for this use case&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;2. &lt;code&gt;@modelcontextprotocol/server-filesystem&lt;/code&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Gives Claude access to project files&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Use in Claude Desktop to read source → generate tests&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Install: configured in &lt;code&gt;claude_desktop_config.json&lt;/code&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;3. Custom Testing MCP (Build This — Highest Value)&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Build a lightweight MCP server that:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Reads a source file&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Extracts function signatures + types&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Returns structured JSON to Claude&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Claude generates tests from structure, not guesswork&lt;br&gt;
&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;

&lt;span class="c1"&gt;// mcp-test-generator/src/index.ts&lt;/span&gt;


&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;Server&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@modelcontextprotocol/sdk/server/index.js&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;


&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;StdioServerTransport&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@modelcontextprotocol/sdk/server/stdio.js&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;


&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nx"&gt;ts&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;typescript&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;





&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;server&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Server&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;test-generator&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;version&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;1.0.0&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;


  &lt;span class="na"&gt;capabilities&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;tools&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;


&lt;span class="p"&gt;});&lt;/span&gt;





&lt;span class="nx"&gt;server&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setRequestHandler&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;tools/call&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;


  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;params&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;extract_signatures&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;


    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;filePath&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;params&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;arguments&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;


    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;signatures&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;extractFunctionSignatures&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;filePath&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// parse AST&lt;/span&gt;


    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;content&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[{&lt;/span&gt; &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;text&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;text&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;stringify&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;signatures&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;}]&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;


  &lt;span class="p"&gt;}&lt;/span&gt;


&lt;span class="p"&gt;});&lt;/span&gt;





&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;extractFunctionSignatures&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;filePath&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;


  &lt;span class="c1"&gt;// Use TypeScript compiler API to extract:&lt;/span&gt;


  &lt;span class="c1"&gt;// - class name&lt;/span&gt;


  &lt;span class="c1"&gt;// - method names&lt;/span&gt;


  &lt;span class="c1"&gt;// - parameter types&lt;/span&gt;


  &lt;span class="c1"&gt;// - return types&lt;/span&gt;


  &lt;span class="c1"&gt;// - injected dependencies (constructor params)&lt;/span&gt;


  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;program&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;ts&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;createProgram&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="nx"&gt;filePath&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="p"&gt;{});&lt;/span&gt;


  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;sourceFile&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;program&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getSourceFile&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;filePath&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;


  &lt;span class="c1"&gt;// ... AST traversal&lt;/span&gt;


  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;className&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;methods&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;dependencies&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;


&lt;span class="p"&gt;}&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Why this matters:&lt;/strong&gt; When Claude receives typed signatures instead of raw source code, it cannot hallucinate — it generates tests from concrete types, not guesses.&lt;/p&gt;

&lt;h3&gt;
  
  
  5.3 Claude Desktop MCP Config
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="err"&gt;//&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;~/Library/Application&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;Support/Claude/claude_desktop_config.json&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;(macOS)&lt;/span&gt;&lt;span class="w"&gt;


&lt;/span&gt;&lt;span class="err"&gt;//&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;%APPDATA%\Claude\claude_desktop_config.json&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;(Windows)&lt;/span&gt;&lt;span class="w"&gt;


&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;


  &lt;/span&gt;&lt;span class="nl"&gt;"mcpServers"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;


    &lt;/span&gt;&lt;span class="nl"&gt;"filesystem"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;


      &lt;/span&gt;&lt;span class="nl"&gt;"command"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"npx"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;


      &lt;/span&gt;&lt;span class="nl"&gt;"args"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"-y"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"@modelcontextprotocol/server-filesystem"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"/path/to/your/project"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;


    &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;


    &lt;/span&gt;&lt;span class="nl"&gt;"test-generator"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;


      &lt;/span&gt;&lt;span class="nl"&gt;"command"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"node"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;


      &lt;/span&gt;&lt;span class="nl"&gt;"args"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"/path/to/your/mcp-test-generator/dist/index.js"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;


    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;


  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;


&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;


&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  5.4 Cursor MCP Config
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="err"&gt;//&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;.cursor/mcp.json&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;(project-level)&lt;/span&gt;&lt;span class="w"&gt;


&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;


  &lt;/span&gt;&lt;span class="nl"&gt;"mcpServers"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;


    &lt;/span&gt;&lt;span class="nl"&gt;"test-generator"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;


      &lt;/span&gt;&lt;span class="nl"&gt;"command"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"node"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;


      &lt;/span&gt;&lt;span class="nl"&gt;"args"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"./tools/mcp-test-generator/dist/index.js"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;


    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;


  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;


&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;


&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Part 6 — Anti-Hallucination Prompt Templates
&lt;/h2&gt;

&lt;p&gt;The root cause of AI hallucination in tests: AI invents method names, wrong mock structures, non-existent imports. These prompts eliminate that.&lt;/p&gt;

&lt;h3&gt;
  
  
  6.1 Cursor Cmd+K Prompt (Use This Exactly)
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;

Generate a unit &lt;span class="nb"&gt;test &lt;/span&gt;file &lt;span class="k"&gt;for &lt;/span&gt;this &lt;span class="o"&gt;[&lt;/span&gt;NestJS service / React component / Python class / Angular service / Laravel service].





Rules:


- Library: &lt;span class="o"&gt;[&lt;/span&gt;Jest / Vitest / pytest / Jest / Pest]


- Test only THIS file — no integration


- Mock ALL dependencies listed &lt;span class="k"&gt;in &lt;/span&gt;the constructor/props


- Follow AAA pattern with comments


- Minimum 4 &lt;span class="nb"&gt;test &lt;/span&gt;cases per public method


- Use ONLY methods/properties that exist &lt;span class="k"&gt;in &lt;/span&gt;this &lt;span class="nb"&gt;source &lt;/span&gt;file


- Do NOT import anything not shown &lt;span class="k"&gt;in &lt;/span&gt;the &lt;span class="nb"&gt;source&lt;/span&gt;


- Naming: &lt;span class="s2"&gt;"should [behavior] when [condition]"&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  6.2 Claude Prompt (For CLAUDE.md aware sessions)
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight markdown"&gt;&lt;code&gt;

Read [filename].&lt;span class="sb"&gt;


&lt;/span&gt;Extract:&lt;span class="sb"&gt;


&lt;/span&gt;&lt;span class="p"&gt;1.&lt;/span&gt; Class/function name&lt;span class="sb"&gt;


&lt;/span&gt;&lt;span class="p"&gt;2.&lt;/span&gt; All public methods with parameter types and return types&lt;span class="sb"&gt;


&lt;/span&gt;&lt;span class="p"&gt;3.&lt;/span&gt; All constructor dependencies (for mocking)&lt;span class="sb"&gt;





&lt;/span&gt;Then generate the unit test file following CLAUDE.md rules.&lt;span class="sb"&gt;


&lt;/span&gt;Do NOT assume any method exists unless you can see it in the source.&lt;span class="sb"&gt;


&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  6.3 Batch Test Generation Prompt
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;

&lt;span class="k"&gt;For&lt;/span&gt; &lt;span class="n"&gt;each&lt;/span&gt; &lt;span class="n"&gt;file&lt;/span&gt; &lt;span class="n"&gt;in&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;directory&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="n"&gt;generate&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="n"&gt;corresponding&lt;/span&gt; &lt;span class="mf"&gt;.&lt;/span&gt;&lt;span class="n"&gt;spec&lt;/span&gt;&lt;span class="mf"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ts&lt;/span&gt; &lt;span class="n"&gt;file&lt;/span&gt;&lt;span class="mf"&gt;.&lt;/span&gt;


&lt;span class="nc"&gt;Process&lt;/span&gt; &lt;span class="n"&gt;one&lt;/span&gt; &lt;span class="n"&gt;file&lt;/span&gt; &lt;span class="n"&gt;at&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="mf"&gt;.&lt;/span&gt;


&lt;span class="k"&gt;For&lt;/span&gt; &lt;span class="n"&gt;each&lt;/span&gt; &lt;span class="n"&gt;file&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;


  &lt;span class="mf"&gt;1.&lt;/span&gt; &lt;span class="nc"&gt;Read&lt;/span&gt; &lt;span class="n"&gt;the&lt;/span&gt; &lt;span class="n"&gt;source&lt;/span&gt;


  &lt;span class="mf"&gt;2.&lt;/span&gt; &lt;span class="k"&gt;List&lt;/span&gt; &lt;span class="n"&gt;the&lt;/span&gt; &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;methods&lt;/span&gt; &lt;span class="n"&gt;you&lt;/span&gt; &lt;span class="nf"&gt;found&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;confirm&lt;/span&gt; &lt;span class="n"&gt;before&lt;/span&gt; &lt;span class="n"&gt;generating&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;


  &lt;span class="mf"&gt;3.&lt;/span&gt; &lt;span class="nc"&gt;Generate&lt;/span&gt; &lt;span class="n"&gt;the&lt;/span&gt; &lt;span class="n"&gt;test&lt;/span&gt; &lt;span class="n"&gt;file&lt;/span&gt;


  &lt;span class="mf"&gt;4.&lt;/span&gt; &lt;span class="nc"&gt;Show&lt;/span&gt; &lt;span class="n"&gt;the&lt;/span&gt; &lt;span class="n"&gt;test&lt;/span&gt; &lt;span class="n"&gt;file&lt;/span&gt; &lt;span class="n"&gt;path&lt;/span&gt;





&lt;span class="k"&gt;Do&lt;/span&gt; &lt;span class="n"&gt;not&lt;/span&gt; &lt;span class="n"&gt;proceed&lt;/span&gt; &lt;span class="n"&gt;to&lt;/span&gt; &lt;span class="n"&gt;the&lt;/span&gt; &lt;span class="n"&gt;next&lt;/span&gt; &lt;span class="n"&gt;file&lt;/span&gt; &lt;span class="n"&gt;until&lt;/span&gt; &lt;span class="n"&gt;the&lt;/span&gt; &lt;span class="n"&gt;current&lt;/span&gt; &lt;span class="n"&gt;one&lt;/span&gt; &lt;span class="n"&gt;is&lt;/span&gt; &lt;span class="n"&gt;confirmed&lt;/span&gt;&lt;span class="mf"&gt;.&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Part 7 — Project Structure Convention
&lt;/h2&gt;

&lt;p&gt;All stacks follow the same proximity principle: &lt;strong&gt;test file lives next to source file&lt;/strong&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Node.js / NestJS / Angular
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight markdown"&gt;&lt;code&gt;

src/&lt;span class="sb"&gt;


&lt;/span&gt;  modules/&lt;span class="sb"&gt;


    users/


      users.service.ts


      users.service.spec.ts        ← unit test


      users.repository.ts


      users.repository.spec.ts     ← unit test


      users.guard.ts


      users.guard.spec.ts          ← unit test


&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  React
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

src/


  components/


    UserCard/


      UserCard.tsx


      UserCard.test.tsx            ← unit test


      UserCard.stories.tsx         ← storybook (optional)


  hooks/


    useUserData.ts


    useUserData.test.ts            ← unit test


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Python
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

app/


  services/


    user_service.py


tests/


  unit/


    services/


      test_user_service.py        ← mirrors app/ structure


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Laravel
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

app/


  Services/


    UserService.php


tests/


  Unit/


    Services/


      UserServiceTest.php         ← mirrors app/ structure


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Part 8 — CI Enforcement
&lt;/h2&gt;

&lt;p&gt;All of this means nothing without enforcement. The pipeline is the final gate.&lt;/p&gt;

&lt;h3&gt;
  
  
  GitHub Actions — Multi-stack parallel
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;

&lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Unit Tests&lt;/span&gt;





&lt;span class="na"&gt;on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;push&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;pull_request&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;





&lt;span class="na"&gt;jobs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;


  &lt;span class="na"&gt;nestjs-unit&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;


    &lt;span class="na"&gt;runs-on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;ubuntu-latest&lt;/span&gt;


    &lt;span class="na"&gt;steps&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;


      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;actions/checkout@v4&lt;/span&gt;


      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;actions/setup-node@v4&lt;/span&gt;


        &lt;span class="na"&gt;with&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;{&lt;/span&gt; &lt;span class="nv"&gt;node-version&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;20'&lt;/span&gt; &lt;span class="pi"&gt;}&lt;/span&gt;


      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;npm ci&lt;/span&gt;


      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;npm run test:unit -- --coverage --coverageThreshold='{"global":{"lines":80}}'&lt;/span&gt;





  &lt;span class="na"&gt;react-unit&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;


    &lt;span class="na"&gt;runs-on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;ubuntu-latest&lt;/span&gt;


    &lt;span class="na"&gt;steps&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;


      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;actions/checkout@v4&lt;/span&gt;


      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;actions/setup-node@v4&lt;/span&gt;


        &lt;span class="na"&gt;with&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;{&lt;/span&gt; &lt;span class="nv"&gt;node-version&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;20'&lt;/span&gt; &lt;span class="pi"&gt;}&lt;/span&gt;


      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;npm ci&lt;/span&gt;


      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;npx vitest run --coverage&lt;/span&gt;





  &lt;span class="na"&gt;python-unit&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;


    &lt;span class="na"&gt;runs-on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;ubuntu-latest&lt;/span&gt;


    &lt;span class="na"&gt;steps&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;


      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;actions/checkout@v4&lt;/span&gt;


      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;actions/setup-python@v5&lt;/span&gt;


        &lt;span class="na"&gt;with&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;{&lt;/span&gt; &lt;span class="nv"&gt;python-version&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;3.12'&lt;/span&gt; &lt;span class="pi"&gt;}&lt;/span&gt;


      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;pip install -r requirements-dev.txt&lt;/span&gt;


      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;pytest tests/unit/ --cov=app --cov-fail-under=80&lt;/span&gt;





  &lt;span class="na"&gt;laravel-unit&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;


    &lt;span class="na"&gt;runs-on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;ubuntu-latest&lt;/span&gt;


    &lt;span class="na"&gt;steps&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;


      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;actions/checkout@v4&lt;/span&gt;


      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;shivammathur/setup-php@v2&lt;/span&gt;


        &lt;span class="na"&gt;with&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;{&lt;/span&gt; &lt;span class="nv"&gt;php-version&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;8.3'&lt;/span&gt; &lt;span class="pi"&gt;}&lt;/span&gt;


      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;composer install&lt;/span&gt;


      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;./vendor/bin/pest --coverage --min=80&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Pre-commit Hook (Husky — Node stacks)
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="err"&gt;//&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;package.json&lt;/span&gt;&lt;span class="w"&gt;


&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;


  &lt;/span&gt;&lt;span class="nl"&gt;"lint-staged"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;


    &lt;/span&gt;&lt;span class="nl"&gt;"src/**/*.service.ts"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"jest --findRelatedTests --passWithNoTests"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;


    &lt;/span&gt;&lt;span class="nl"&gt;"src/**/*.tsx"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"vitest related --run"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;


  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;


&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;


&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Part 9 — Quick Start Checklist
&lt;/h2&gt;

&lt;h3&gt;
  
  
  New Project
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

□ Install test library (one per stack — see Part 1)


□ Configure jest.config.ts / vitest.config.ts / pytest.ini / pest.php


□ Create .cursor/rules/ directory with all rule files from Part 3


□ Create CLAUDE.md at project root from Part 4


□ Add coverage thresholds to config


□ Add pre-commit hooks (Husky for Node, pre-commit for Python)


□ Add CI workflow from Part 8


□ Create test factory files (one per major entity)


□ Write first failing test → implement → green → commit


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Existing Project
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

□ Add test library without touching existing code


□ Add .cursor/rules/ + CLAUDE.md


□ Run coverage on existing code → document current baseline


□ Pick 3 critical services → generate tests → set as new baseline


□ Add CI with threshold = current baseline (not ideal — current)


□ Raise threshold by 5% per sprint


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Appendix — Install Commands Per Stack
&lt;/h2&gt;

&lt;h3&gt;
  
  
  NestJS
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;

npm &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;--save-dev&lt;/span&gt; jest ts-jest @types/jest @nestjs/testing jest-mock-extended @golevelup/ts-jest


npx ts-jest config:init


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  React (Vite)
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;

npm &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;--save-dev&lt;/span&gt; vitest @vitest/coverage-v8 @testing-library/react @testing-library/user-event @testing-library/jest-dom jsdom


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Python
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;

pip &lt;span class="nb"&gt;install &lt;/span&gt;pytest pytest-cov pytest-mock pytest-asyncio factory-boy


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Angular
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;

ng add @angular-builders/jest


npm &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;--save-dev&lt;/span&gt; jest jest-preset-angular @types/jest


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Laravel
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;

composer require pestphp/pest pestphp/pest-plugin-laravel &lt;span class="nt"&gt;--dev&lt;/span&gt;


./vendor/bin/pest &lt;span class="nt"&gt;--init&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;p&gt;&lt;em&gt;Last updated: 2025 — verify library major versions before adopting&lt;/em&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>javascript</category>
      <category>llm</category>
      <category>testing</category>
    </item>
    <item>
      <title>Unit Test AI Guide — Zero Hallucination, Cross-Stack Standard</title>
      <dc:creator>Bhaumik</dc:creator>
      <pubDate>Fri, 19 Jun 2026 11:38:06 +0000</pubDate>
      <link>https://dev.to/bhaumik-viitor/unit-test-ai-guide-zero-hallucination-cross-stack-standard-1p28</link>
      <guid>https://dev.to/bhaumik-viitor/unit-test-ai-guide-zero-hallucination-cross-stack-standard-1p28</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Focus:&lt;/strong&gt; Unit Tests ONLY — no integration, no E2E  &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Stacks:&lt;/strong&gt; Node.js (NestJS/Express) · React.js · Python · Angular · Laravel  &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Goal:&lt;/strong&gt; AI generates unit tests consistently, deterministically, without hallucination  &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;IDE:&lt;/strong&gt; Cursor (Primary) + Claude (Secondary)&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  Part 1 — Best Single Library Per Stack (Final Decision)
&lt;/h2&gt;

&lt;p&gt;Do not mix libraries. Pick one per stack, configure it fully, never deviate.&lt;/p&gt;

&lt;p&gt;| Stack | Library | Why This One |&lt;/p&gt;

&lt;p&gt;|---|---|---|&lt;/p&gt;

&lt;p&gt;| &lt;strong&gt;Node.js / NestJS / Express&lt;/strong&gt; | &lt;code&gt;Jest&lt;/code&gt; | Native DI mocking, &lt;code&gt;@nestjs/testing&lt;/code&gt; built around it, widest ecosystem |&lt;/p&gt;

&lt;p&gt;| &lt;strong&gt;React.js&lt;/strong&gt; | &lt;code&gt;Vitest&lt;/code&gt; + &lt;code&gt;@testing-library/react&lt;/code&gt; | Native Vite/ESM support, Jest-compatible API, 3–10x faster |&lt;/p&gt;

&lt;p&gt;| &lt;strong&gt;Python&lt;/strong&gt; | &lt;code&gt;pytest&lt;/code&gt; | De facto standard, fixture system eliminates boilerplate, best plugin ecosystem |&lt;/p&gt;

&lt;p&gt;| &lt;strong&gt;Angular&lt;/strong&gt; | &lt;code&gt;Jest&lt;/code&gt; (replace Karma) | Karma is deprecated in Angular 17+; Jest is the official migration target |&lt;/p&gt;

&lt;p&gt;| &lt;strong&gt;Laravel&lt;/strong&gt; | &lt;code&gt;Pest&lt;/code&gt; | Modern syntax, built on PHPUnit, higher signal-to-noise ratio |&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Rule:&lt;/strong&gt; If someone suggests a second library for the same stack, reject it. One library per stack, configured once, followed always.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  Part 2 — IDE: Cursor (Only Choice for This Goal)
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Why Cursor and Not VS Code / WebStorm
&lt;/h3&gt;

&lt;p&gt;| Capability | Cursor | VS Code + Copilot | WebStorm |&lt;/p&gt;

&lt;p&gt;|---|---|---|---|&lt;/p&gt;

&lt;p&gt;| Project-level AI rules | ✅ &lt;code&gt;.cursor/rules/&lt;/code&gt; | ❌ | ❌ |&lt;/p&gt;

&lt;p&gt;| Codebase-aware context | ✅ &lt;code&gt;@codebase&lt;/code&gt; | Partial | Partial |&lt;/p&gt;

&lt;p&gt;| Run terminal + read output | ✅ Composer | ❌ | ❌ |&lt;/p&gt;

&lt;p&gt;| Multi-file generation | ✅ Agent mode | Limited | ❌ |&lt;/p&gt;

&lt;p&gt;| Custom instructions per filetype | ✅ | ❌ | ❌ |&lt;/p&gt;

&lt;p&gt;| MCP server integration | ✅ | ❌ | ❌ |&lt;/p&gt;

&lt;p&gt;Cursor's &lt;code&gt;.cursor/rules/&lt;/code&gt; system is the &lt;strong&gt;only IDE-native mechanism&lt;/strong&gt; that injects persistent, project-scoped instructions into every AI interaction — this is what prevents hallucination at the source.&lt;/p&gt;

&lt;h3&gt;
  
  
  Cursor Setup for This Project
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

project-root/


├── .cursor/


│   └── rules/


│       ├── unit-test-global.mdc       ← applies to all files


│       ├── unit-test-nestjs.mdc       ← applies to *.service.ts, *.guard.ts


│       ├── unit-test-react.mdc        ← applies to *.tsx, *.component.tsx


│       ├── unit-test-python.mdc       ← applies to *.py


│       ├── unit-test-angular.mdc      ← applies to *.component.ts, *.service.ts


│       └── unit-test-laravel.mdc      ← applies to *Service.php, *Model.php


├── CLAUDE.md                          ← Claude project memory file


└── ...


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Part 3 — Cursor Rules Files (Anti-Hallucination Core)
&lt;/h2&gt;

&lt;p&gt;These files are injected into every AI prompt automatically when working on matching files.&lt;/p&gt;

&lt;h3&gt;
  
  
  3.1 Global Unit Test Rule
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;File: &lt;code&gt;.cursor/rules/unit-test-global.mdc&lt;/code&gt;&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight markdown"&gt;&lt;code&gt;&lt;span class="p"&gt;

---

&lt;/span&gt;
description: Global unit test rules — applies to all files in this project&lt;span class="sb"&gt;


&lt;/span&gt;globs: ["&lt;span class="gs"&gt;**/*.spec.ts", "**&lt;/span&gt;/&lt;span class="ge"&gt;*.test.ts", "**/*&lt;/span&gt;.spec.tsx", "&lt;span class="gs"&gt;**/*_test.py", "**&lt;/span&gt;/Test&lt;span class="err"&gt;*&lt;/span&gt;.php"]&lt;span class="sb"&gt;


&lt;/span&gt;alwaysApply: true&lt;span class="sb"&gt;


&lt;/span&gt;&lt;span class="p"&gt;---




&lt;/span&gt;
&lt;span class="gh"&gt;# Unit Test Contract — MUST FOLLOW, NO EXCEPTIONS&lt;/span&gt;&lt;span class="sb"&gt;





&lt;/span&gt;&lt;span class="gu"&gt;## What is a unit test here&lt;/span&gt;&lt;span class="sb"&gt;


&lt;/span&gt;&lt;span class="p"&gt;-&lt;/span&gt; Tests ONE class or function in complete isolation&lt;span class="sb"&gt;


&lt;/span&gt;&lt;span class="p"&gt;-&lt;/span&gt; ALL external dependencies are mocked — no real DB, no real HTTP, no real file system&lt;span class="sb"&gt;


&lt;/span&gt;&lt;span class="p"&gt;-&lt;/span&gt; Each test runs independently — no shared mutable state between tests&lt;span class="sb"&gt;


&lt;/span&gt;&lt;span class="p"&gt;-&lt;/span&gt; Runs in &amp;lt; 100ms&lt;span class="sb"&gt;





&lt;/span&gt;&lt;span class="gu"&gt;## Structure: AAA — Always, Without Exception&lt;/span&gt;&lt;span class="sb"&gt;


&lt;/span&gt;Every test MUST have these three sections, with comments:&lt;span class="sb"&gt;


&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;// Arrange — set up inputs, mocks, expected values&lt;/p&gt;

&lt;p&gt;// Act — call the single function/method under test&lt;/p&gt;

&lt;p&gt;// Assert — verify exactly one outcome&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;




## Naming Convention — Mandatory


- File: `[module-name].spec.ts` or `[module-name].unit.spec.ts`


- Describe block: exact class or function name


- It/test block: "should [expected behavior] when [specific condition]"


  GOOD: "should throw NotFoundException when user does not exist"


  BAD:  "user not found", "test 1", "works correctly"





## What to test per function — minimum coverage


1. Happy path — valid input → expected output


2. Null/undefined input — how does it fail safely


3. Empty input — empty string, empty array, zero


4. Error path — when dependency throws, what happens


5. Boundary — max length, negative numbers, boolean edge





## What NOT to include in unit tests


- Database queries (mock the repository)


- HTTP calls (mock the service/axios/fetch)


- File system operations (mock fs)


- Timer behavior (use jest.useFakeTimers)


- Random values (mock Math.random or faker with fixed seed)





## AI Instruction


When asked to generate a unit test:


1. READ the function signature and types first


2. IDENTIFY all dependencies (constructor args, imported modules)


3. MOCK every dependency — never use real implementations


4. Generate minimum 4 test cases per method (happy, null, error, edge)


5. NEVER import from test doubles or assume what isn't in the source file


6. If you are unsure of a type — ASK, do not assume


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h3&gt;
  
  
  3.2 NestJS Rule
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;File: &lt;code&gt;.cursor/rules/unit-test-nestjs.mdc&lt;/code&gt;&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight markdown"&gt;&lt;code&gt;&lt;span class="p"&gt;

---

&lt;/span&gt;
description: NestJS unit test rules&lt;span class="sb"&gt;


&lt;/span&gt;globs: ["src/&lt;span class="gs"&gt;**/*.service.ts", "src/**&lt;/span&gt;/&lt;span class="ge"&gt;*.guard.ts", "src/**/*&lt;/span&gt;.interceptor.ts", "src/&lt;span class="ge"&gt;**&lt;/span&gt;/&lt;span class="err"&gt;*&lt;/span&gt;.pipe.ts"]&lt;span class="sb"&gt;


&lt;/span&gt;&lt;span class="p"&gt;---




&lt;/span&gt;
&lt;span class="gh"&gt;# NestJS Unit Test Rules&lt;/span&gt;&lt;span class="sb"&gt;





&lt;/span&gt;&lt;span class="gu"&gt;## Library: Jest + @nestjs/testing + jest-mock-extended&lt;/span&gt;&lt;span class="sb"&gt;





&lt;/span&gt;&lt;span class="gu"&gt;## Always use Test.createTestingModule&lt;/span&gt;&lt;span class="sb"&gt;


&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;&lt;br&gt;
typescript&lt;/p&gt;

&lt;p&gt;const module = await Test.createTestingModule({&lt;/p&gt;

&lt;p&gt;providers: [&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;SubjectService,


{ provide: DependencyService, useValue: mockDependency }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;p&gt;]&lt;/p&gt;

&lt;p&gt;}).compile();&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;




## Mock Pattern — jest-mock-extended


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;&lt;br&gt;
typescript&lt;/p&gt;

&lt;p&gt;import { createMock } from '@golevelup/ts-jest';&lt;/p&gt;

&lt;p&gt;// OR&lt;/p&gt;

&lt;p&gt;import { mock } from 'jest-mock-extended';&lt;/p&gt;

&lt;p&gt;const mockUserRepo = mock();&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;




## Never


- Never use `new SubjectService()` directly — always use TestingModule


- Never let `useValue` contain real implementations


- Never test more than one service per describe block





## Repository Mock Template


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;&lt;br&gt;
typescript&lt;/p&gt;

&lt;p&gt;const mockRepo = {&lt;/p&gt;

&lt;p&gt;findOne: jest.fn(),&lt;/p&gt;

&lt;p&gt;save: jest.fn(),&lt;/p&gt;

&lt;p&gt;delete: jest.fn(),&lt;/p&gt;

&lt;p&gt;findAll: jest.fn(),&lt;/p&gt;

&lt;p&gt;update: jest.fn(),&lt;/p&gt;

&lt;p&gt;};&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;




## Required imports for every NestJS spec file


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;&lt;br&gt;
typescript&lt;/p&gt;

&lt;p&gt;import { Test, TestingModule } from '@nestjs/testing';&lt;/p&gt;

&lt;p&gt;import { NotFoundException, BadRequestException } from '@nestjs/common';&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;&lt;br&gt;
markdown&lt;/p&gt;


&lt;h3&gt;
  
  
  3.3 React Rule
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;File: &lt;code&gt;.cursor/rules/unit-test-react.mdc&lt;/code&gt;&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight markdown"&gt;&lt;code&gt;&lt;span class="p"&gt;

---

&lt;/span&gt;
description: React unit test rules&lt;span class="sb"&gt;


&lt;/span&gt;globs: ["src/&lt;span class="gs"&gt;**/*.tsx", "src/**&lt;/span&gt;/&lt;span class="ge"&gt;*.component.tsx", "src/hooks/**/*&lt;/span&gt;.ts"]&lt;span class="sb"&gt;


&lt;/span&gt;&lt;span class="p"&gt;---




&lt;/span&gt;
&lt;span class="gh"&gt;# React Unit Test Rules&lt;/span&gt;&lt;span class="sb"&gt;





&lt;/span&gt;&lt;span class="gu"&gt;## Library: Vitest + @testing-library/react + @testing-library/user-event&lt;/span&gt;&lt;span class="sb"&gt;





&lt;/span&gt;&lt;span class="gu"&gt;## Required setup in vitest.config.ts&lt;/span&gt;&lt;span class="sb"&gt;


&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;&lt;br&gt;
typescript&lt;/p&gt;

&lt;p&gt;export default defineConfig({&lt;/p&gt;

&lt;p&gt;test: {&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;environment: 'jsdom',


globals: true,


setupFiles: ['./src/test/setup.ts']
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;p&gt;}&lt;/p&gt;

&lt;p&gt;})&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;




## setup.ts


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;&lt;br&gt;
typescript&lt;/p&gt;

&lt;p&gt;import '@testing-library/jest-dom';&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;




## Component test structure


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;&lt;br&gt;
typescript&lt;/p&gt;

&lt;p&gt;import { render, screen } from '@testing-library/react';&lt;/p&gt;

&lt;p&gt;import userEvent from '@testing-library/user-event';&lt;/p&gt;

&lt;p&gt;import { vi } from 'vitest';&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;




## Mocking rules for React


- Mock ALL hooks that call APIs: `vi.mock('../hooks/useUsers')`


- Mock ALL context providers — wrap with test-specific providers


- Mock router: use `MemoryRouter` from react-router-dom


- NEVER mock internal state (useState) — test behavior, not implementation





## Query priority (RTL best practice — mandatory)


1. getByRole — prefer always


2. getByLabelText — for forms


3. getByText — for content


4. getByTestId — LAST RESORT only, requires data-testid attribute





## User event — always use userEvent, never fireEvent


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;&lt;br&gt;
typescript&lt;/p&gt;

&lt;p&gt;const user = userEvent.setup();&lt;/p&gt;

&lt;p&gt;await user.click(button);&lt;/p&gt;

&lt;p&gt;await user.type(input, 'value');&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;




## Custom hook testing


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;&lt;br&gt;
typescript&lt;/p&gt;

&lt;p&gt;import { renderHook, act } from '@testing-library/react';&lt;/p&gt;

&lt;p&gt;const { result } = renderHook(() =&amp;gt; useMyHook());&lt;/p&gt;

&lt;p&gt;act(() =&amp;gt; result.current.doSomething());&lt;/p&gt;

&lt;p&gt;expect(result.current.value).toBe('expected');&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;&lt;br&gt;
typescript&lt;/p&gt;


&lt;h3&gt;
  
  
  3.4 Python Rule
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;File: &lt;code&gt;.cursor/rules/unit-test-python.mdc&lt;/code&gt;&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight markdown"&gt;&lt;code&gt;&lt;span class="p"&gt;

---

&lt;/span&gt;
description: Python unit test rules&lt;span class="sb"&gt;


&lt;/span&gt;globs: ["&lt;span class="gs"&gt;**/*.py", "!**&lt;/span&gt;/&lt;span class="ge"&gt;*migrations*&lt;/span&gt;"]&lt;span class="sb"&gt;


&lt;/span&gt;&lt;span class="p"&gt;---




&lt;/span&gt;
&lt;span class="gh"&gt;# Python Unit Test Rules&lt;/span&gt;&lt;span class="sb"&gt;





&lt;/span&gt;&lt;span class="gu"&gt;## Library: pytest + pytest-mock + factory-boy&lt;/span&gt;&lt;span class="sb"&gt;





&lt;/span&gt;&lt;span class="gu"&gt;## File naming&lt;/span&gt;&lt;span class="sb"&gt;


&lt;/span&gt;&lt;span class="p"&gt;-&lt;/span&gt; Source: &lt;span class="sb"&gt;`app/services/user_service.py`


&lt;/span&gt;&lt;span class="p"&gt;-&lt;/span&gt; Test:   &lt;span class="sb"&gt;`tests/unit/test_user_service.py`


&lt;/span&gt;&lt;span class="p"&gt;-&lt;/span&gt; ALWAYS mirror the source directory structure under tests/unit/&lt;span class="sb"&gt;





&lt;/span&gt;&lt;span class="gu"&gt;## Class under test — always use dependency injection&lt;/span&gt;&lt;span class="sb"&gt;


&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;&lt;br&gt;
python&lt;/p&gt;
&lt;h1&gt;
  
  
  GOOD — injectable dependency
&lt;/h1&gt;

&lt;p&gt;class UserService:&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;def __init__(self, repo: UserRepository):


    self.repo = repo
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;h1&gt;
  
  
  BAD — untestable
&lt;/h1&gt;

&lt;p&gt;class UserService:&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;def __init__(self):


    self.repo = UserRepository()  # can't mock this
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;




## Mock pattern — pytest-mock (mocker fixture)


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;p&gt;&lt;br&gt;
python&lt;/p&gt;

&lt;p&gt;def test_raises_when_user_not_found(mocker):&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;mock_repo = mocker.Mock()


mock_repo.find_by_id.return_value = None


service = UserService(mock_repo)


with pytest.raises(UserNotFoundException):


    service.get_user("missing-id")
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;




## Async tests — pytest-asyncio


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;p&gt;&lt;br&gt;
python&lt;/p&gt;

&lt;p&gt;import pytest&lt;/p&gt;

&lt;p&gt;@pytest.mark.asyncio&lt;/p&gt;

&lt;p&gt;async def test_async_service(mocker):&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;mock_repo = mocker.AsyncMock()


...
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;




## Fixture pattern — for shared setup


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;p&gt;&lt;br&gt;
python&lt;/p&gt;

&lt;p&gt;@pytest.fixture&lt;/p&gt;

&lt;p&gt;def user_service(mocker):&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;repo = mocker.Mock()


return UserService(repo), repo
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;p&gt;def test_get_user_happy_path(user_service):&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;service, repo = user_service


repo.find_by_id.return_value = User(id="1", email="a@b.com")


result = service.get_user("1")


assert result.email == "a@b.com"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;




## Naming


- File: `test_[module_name].py`


- Function: `test_[expected_behavior]_when_[condition]`


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;p&gt;&lt;br&gt;
markdown&lt;/p&gt;


&lt;h3&gt;
  
  
  3.5 Angular Rule
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;File: &lt;code&gt;.cursor/rules/unit-test-angular.mdc&lt;/code&gt;&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight markdown"&gt;&lt;code&gt;&lt;span class="p"&gt;

---

&lt;/span&gt;
description: Angular unit test rules&lt;span class="sb"&gt;


&lt;/span&gt;globs: ["src/app/&lt;span class="gs"&gt;**/*.component.ts", "src/app/**&lt;/span&gt;/&lt;span class="ge"&gt;*.service.ts", "src/app/**/*&lt;/span&gt;.pipe.ts", "src/app/&lt;span class="ge"&gt;**&lt;/span&gt;/&lt;span class="err"&gt;*&lt;/span&gt;.guard.ts"]&lt;span class="sb"&gt;


&lt;/span&gt;&lt;span class="p"&gt;---




&lt;/span&gt;
&lt;span class="gh"&gt;# Angular Unit Test Rules&lt;/span&gt;&lt;span class="sb"&gt;





&lt;/span&gt;&lt;span class="gu"&gt;## Library: Jest (NOT Karma — Karma is deprecated Angular 17+)&lt;/span&gt;&lt;span class="sb"&gt;





&lt;/span&gt;&lt;span class="gu"&gt;## Migration from Karma to Jest (one-time)&lt;/span&gt;&lt;span class="sb"&gt;


&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;&lt;br&gt;
bash&lt;/p&gt;

&lt;p&gt;ng add @angular-builders/jest&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;




## TestBed configuration — always minimal


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;&lt;br&gt;
typescript&lt;/p&gt;

&lt;p&gt;await TestBed.configureTestingModule({&lt;/p&gt;

&lt;p&gt;imports: [ComponentUnderTest],  // standalone components&lt;/p&gt;

&lt;p&gt;providers: [&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{ provide: UserService, useValue: mockUserService }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;p&gt;]&lt;/p&gt;

&lt;p&gt;}).compileComponents();&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;




## Service mock pattern


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;&lt;br&gt;
typescript&lt;/p&gt;

&lt;p&gt;const mockUserService = {&lt;/p&gt;

&lt;p&gt;getUser: jest.fn(),&lt;/p&gt;

&lt;p&gt;createUser: jest.fn(),&lt;/p&gt;

&lt;p&gt;};&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;




## Component test — check DOM behavior, not internal state


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;&lt;br&gt;
typescript&lt;/p&gt;

&lt;p&gt;fixture.detectChanges(); // trigger ngOnInit&lt;/p&gt;

&lt;p&gt;const button = fixture.debugElement.query(By.css('[data-testid="submit"]'));&lt;/p&gt;

&lt;p&gt;button.nativeElement.click();&lt;/p&gt;

&lt;p&gt;fixture.detectChanges();&lt;/p&gt;

&lt;p&gt;expect(fixture.debugElement.query(By.css('.error-msg'))).toBeTruthy();&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;




## Pipe test — pure function, no TestBed needed


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;&lt;br&gt;
typescript&lt;/p&gt;

&lt;p&gt;it('should transform date correctly', () =&amp;gt; {&lt;/p&gt;

&lt;p&gt;const pipe = new DateFormatPipe();&lt;/p&gt;

&lt;p&gt;expect(pipe.transform(new Date('2024-01-01'))).toBe('Jan 1, 2024');&lt;/p&gt;

&lt;p&gt;});&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;




## Guard/resolver test — inject and call directly


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;&lt;br&gt;
typescript&lt;/p&gt;

&lt;p&gt;const guard = TestBed.inject(AuthGuard);&lt;/p&gt;

&lt;p&gt;const result = await guard.canActivate(mockRoute, mockState);&lt;/p&gt;

&lt;p&gt;expect(result).toBe(false);&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;&lt;br&gt;
python&lt;/p&gt;


&lt;h3&gt;
  
  
  3.6 Laravel Rule
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;File: &lt;code&gt;.cursor/rules/unit-test-laravel.mdc&lt;/code&gt;&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight markdown"&gt;&lt;code&gt;&lt;span class="p"&gt;

---

&lt;/span&gt;
description: Laravel unit test rules&lt;span class="sb"&gt;


&lt;/span&gt;globs: ["app/Services/&lt;span class="gs"&gt;**/*.php", "app/Models/**&lt;/span&gt;/&lt;span class="ge"&gt;*.php", "app/Http/Requests/**/*&lt;/span&gt;.php", "app/Actions/&lt;span class="ge"&gt;**&lt;/span&gt;/&lt;span class="err"&gt;*&lt;/span&gt;.php"]&lt;span class="sb"&gt;


&lt;/span&gt;&lt;span class="p"&gt;---




&lt;/span&gt;
&lt;span class="gh"&gt;# Laravel Unit Test Rules&lt;/span&gt;&lt;span class="sb"&gt;





&lt;/span&gt;&lt;span class="gu"&gt;## Library: Pest (NOT PHPUnit directly — Pest wraps it with better syntax)&lt;/span&gt;&lt;span class="sb"&gt;





&lt;/span&gt;&lt;span class="gu"&gt;## File location&lt;/span&gt;&lt;span class="sb"&gt;


&lt;/span&gt;&lt;span class="p"&gt;-&lt;/span&gt; Source: &lt;span class="sb"&gt;`app/Services/UserService.php`


&lt;/span&gt;&lt;span class="p"&gt;-&lt;/span&gt; Test:   &lt;span class="sb"&gt;`tests/Unit/Services/UserServiceTest.php`





&lt;/span&gt;&lt;span class="gu"&gt;## Class under test — use constructor injection&lt;/span&gt;&lt;span class="sb"&gt;


&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;&lt;br&gt;
php&lt;/p&gt;

&lt;p&gt;class UserService {&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;public function __construct(


    private readonly UserRepositoryInterface $repo


) {}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;p&gt;}&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;




## Mock pattern — Mockery (included with Pest/PHPUnit)


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;&lt;br&gt;
php&lt;/p&gt;

&lt;p&gt;it('throws exception when user not found', function () {&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// Arrange


$repo = Mockery::mock(UserRepositoryInterface::class);


$repo-&amp;gt;shouldReceive('findById')-&amp;gt;once()-&amp;gt;andReturn(null);


$service = new UserService($repo);





// Act &amp;amp; Assert


expect(fn () =&amp;gt; $service-&amp;gt;getUser('abc'))


    -&amp;gt;toThrow(UserNotFoundException::class);
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;p&gt;});&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;




## Data provider pattern (Pest datasets)


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;&lt;br&gt;
php&lt;/p&gt;

&lt;p&gt;it('validates email format', function (string $email, bool $valid) {&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;expect(validateEmail($email))-&amp;gt;toBe($valid);
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;p&gt;})-&amp;gt;with([&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;['valid@email.com', true],


['notanemail', false],


['', false],


['@nodomain.com', false],
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;p&gt;]);&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;




## What NOT to do in unit tests


- Never call $this-&amp;gt;get() or $this-&amp;gt;post() — that is feature testing


- Never use RefreshDatabase — that is feature/integration testing


- Never resolve from service container — inject directly


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;&lt;br&gt;
markdown&lt;/p&gt;


&lt;h2&gt;
  
  
  Part 4 — CLAUDE.md (Claude Project Memory)
&lt;/h2&gt;

&lt;p&gt;Place this at project root. Claude reads it on every session automatically.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;File: &lt;code&gt;CLAUDE.md&lt;/code&gt;&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight markdown"&gt;&lt;code&gt;

&lt;span class="gh"&gt;# Project: [Your Project Name]&lt;/span&gt;&lt;span class="sb"&gt;


&lt;/span&gt;&lt;span class="gh"&gt;# Claude Unit Test Instructions&lt;/span&gt;&lt;span class="sb"&gt;





&lt;/span&gt;&lt;span class="gu"&gt;## Stack&lt;/span&gt;&lt;span class="sb"&gt;


&lt;/span&gt;&lt;span class="p"&gt;-&lt;/span&gt; Backend: NestJS + TypeScript&lt;span class="sb"&gt;


&lt;/span&gt;&lt;span class="p"&gt;-&lt;/span&gt; Frontend: React + Vite + TypeScript&lt;span class="sb"&gt;


&lt;/span&gt;&lt;span class="p"&gt;-&lt;/span&gt; Testing: Jest (NestJS) + Vitest (React) + Pest (Laravel) + pytest (Python)&lt;span class="sb"&gt;





&lt;/span&gt;&lt;span class="gu"&gt;## Unit Test Rules — NON-NEGOTIABLE&lt;/span&gt;&lt;span class="sb"&gt;





&lt;/span&gt;&lt;span class="gu"&gt;### When asked to generate a unit test:&lt;/span&gt;&lt;span class="sb"&gt;


&lt;/span&gt;&lt;span class="p"&gt;1.&lt;/span&gt; NEVER generate integration or E2E tests unless explicitly asked&lt;span class="sb"&gt;


&lt;/span&gt;&lt;span class="p"&gt;2.&lt;/span&gt; ALWAYS mock every external dependency&lt;span class="sb"&gt;


&lt;/span&gt;&lt;span class="p"&gt;3.&lt;/span&gt; ALWAYS follow AAA (Arrange-Act-Assert) with comments&lt;span class="sb"&gt;


&lt;/span&gt;&lt;span class="p"&gt;4.&lt;/span&gt; ALWAYS generate minimum 4 cases: happy path, null/empty, error thrown, edge case&lt;span class="sb"&gt;


&lt;/span&gt;&lt;span class="p"&gt;5.&lt;/span&gt; NEVER use &lt;span class="sb"&gt;`any`&lt;/span&gt; type in TypeScript tests&lt;span class="sb"&gt;


&lt;/span&gt;&lt;span class="p"&gt;6.&lt;/span&gt; NEVER leave &lt;span class="sb"&gt;`TODO`&lt;/span&gt; comments in generated tests&lt;span class="sb"&gt;





&lt;/span&gt;&lt;span class="gu"&gt;### Naming&lt;/span&gt;&lt;span class="sb"&gt;


&lt;/span&gt;&lt;span class="p"&gt;-&lt;/span&gt; NestJS: &lt;span class="sb"&gt;`[name].service.spec.ts`&lt;/span&gt; inside same directory as source&lt;span class="sb"&gt;


&lt;/span&gt;&lt;span class="p"&gt;-&lt;/span&gt; React: &lt;span class="sb"&gt;`[ComponentName].test.tsx`&lt;/span&gt; inside &lt;span class="sb"&gt;`__tests__/`&lt;/span&gt; or same directory&lt;span class="sb"&gt;


&lt;/span&gt;&lt;span class="p"&gt;-&lt;/span&gt; Python: &lt;span class="sb"&gt;`test_[module].py`&lt;/span&gt; under &lt;span class="sb"&gt;`tests/unit/`


&lt;/span&gt;&lt;span class="p"&gt;-&lt;/span&gt; Laravel: &lt;span class="sb"&gt;`[Name]Test.php`&lt;/span&gt; under &lt;span class="sb"&gt;`tests/Unit/`





&lt;/span&gt;&lt;span class="gu"&gt;### Test should describe BEHAVIOR, not implementation&lt;/span&gt;&lt;span class="sb"&gt;


&lt;/span&gt;GOOD: "should return empty array when no users match search"&lt;span class="sb"&gt;


&lt;/span&gt;BAD: "test getUserByFilter"&lt;span class="sb"&gt;





&lt;/span&gt;&lt;span class="gu"&gt;### If you are unsure of the correct mock structure:&lt;/span&gt;&lt;span class="sb"&gt;


&lt;/span&gt;&lt;span class="p"&gt;-&lt;/span&gt; Ask what the dependency interface looks like&lt;span class="sb"&gt;


&lt;/span&gt;&lt;span class="p"&gt;-&lt;/span&gt; Do NOT invent method names that don't exist in the source&lt;span class="sb"&gt;





&lt;/span&gt;&lt;span class="gu"&gt;### Coverage target: 80% lines, 75% branches per module&lt;/span&gt;&lt;span class="sb"&gt;





&lt;/span&gt;&lt;span class="gu"&gt;## Project Structure Reference&lt;/span&gt;&lt;span class="sb"&gt;


&lt;/span&gt;src/&lt;span class="sb"&gt;


&lt;/span&gt;  modules/&lt;span class="sb"&gt;


    users/


      users.service.ts


      users.service.spec.ts   ← unit test lives here


      users.repository.ts


      users.repository.spec.ts


&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Part 5 — MCP Servers for Unit Testing in Cursor + Claude
&lt;/h2&gt;

&lt;p&gt;MCP (Model Context Protocol) servers extend AI capabilities. For unit testing, these are the relevant ones:&lt;/p&gt;

&lt;h3&gt;
  
  
  5.1 Filesystem MCP (Built-in Cursor — use directly)
&lt;/h3&gt;

&lt;p&gt;Cursor already has filesystem access. No extra MCP needed to read source files and generate tests. The &lt;code&gt;.cursor/rules/&lt;/code&gt; system handles this.&lt;/p&gt;

&lt;h3&gt;
  
  
  5.2 Available MCP Servers for Testing Workflows
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;1. &lt;code&gt;@executeautomation/playwright-mcp-server&lt;/code&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Scope: E2E only — not relevant for unit tests&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Skip for this use case&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;2. &lt;code&gt;@modelcontextprotocol/server-filesystem&lt;/code&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Gives Claude access to project files&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Use in Claude Desktop to read source → generate tests&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Install: configured in &lt;code&gt;claude_desktop_config.json&lt;/code&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;3. Custom Testing MCP (Build This — Highest Value)&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Build a lightweight MCP server that:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Reads a source file&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Extracts function signatures + types&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Returns structured JSON to Claude&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Claude generates tests from structure, not guesswork&lt;br&gt;
&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;

&lt;span class="c1"&gt;// mcp-test-generator/src/index.ts&lt;/span&gt;


&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;Server&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@modelcontextprotocol/sdk/server/index.js&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;


&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;StdioServerTransport&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@modelcontextprotocol/sdk/server/stdio.js&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;


&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nx"&gt;ts&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;typescript&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;





&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;server&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Server&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;test-generator&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;version&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;1.0.0&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;


  &lt;span class="na"&gt;capabilities&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;tools&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;


&lt;span class="p"&gt;});&lt;/span&gt;





&lt;span class="nx"&gt;server&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setRequestHandler&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;tools/call&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;


  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;params&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;extract_signatures&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;


    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;filePath&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;params&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;arguments&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;


    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;signatures&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;extractFunctionSignatures&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;filePath&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// parse AST&lt;/span&gt;


    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;content&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[{&lt;/span&gt; &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;text&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;text&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;stringify&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;signatures&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;}]&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;


  &lt;span class="p"&gt;}&lt;/span&gt;


&lt;span class="p"&gt;});&lt;/span&gt;





&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;extractFunctionSignatures&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;filePath&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;


  &lt;span class="c1"&gt;// Use TypeScript compiler API to extract:&lt;/span&gt;


  &lt;span class="c1"&gt;// - class name&lt;/span&gt;


  &lt;span class="c1"&gt;// - method names&lt;/span&gt;


  &lt;span class="c1"&gt;// - parameter types&lt;/span&gt;


  &lt;span class="c1"&gt;// - return types&lt;/span&gt;


  &lt;span class="c1"&gt;// - injected dependencies (constructor params)&lt;/span&gt;


  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;program&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;ts&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;createProgram&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="nx"&gt;filePath&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="p"&gt;{});&lt;/span&gt;


  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;sourceFile&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;program&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getSourceFile&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;filePath&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;


  &lt;span class="c1"&gt;// ... AST traversal&lt;/span&gt;


  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;className&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;methods&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;dependencies&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;


&lt;span class="p"&gt;}&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Why this matters:&lt;/strong&gt; When Claude receives typed signatures instead of raw source code, it cannot hallucinate — it generates tests from concrete types, not guesses.&lt;/p&gt;

&lt;h3&gt;
  
  
  5.3 Claude Desktop MCP Config
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="err"&gt;//&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;~/Library/Application&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;Support/Claude/claude_desktop_config.json&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;(macOS)&lt;/span&gt;&lt;span class="w"&gt;


&lt;/span&gt;&lt;span class="err"&gt;//&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;%APPDATA%\Claude\claude_desktop_config.json&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;(Windows)&lt;/span&gt;&lt;span class="w"&gt;


&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;


  &lt;/span&gt;&lt;span class="nl"&gt;"mcpServers"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;


    &lt;/span&gt;&lt;span class="nl"&gt;"filesystem"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;


      &lt;/span&gt;&lt;span class="nl"&gt;"command"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"npx"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;


      &lt;/span&gt;&lt;span class="nl"&gt;"args"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"-y"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"@modelcontextprotocol/server-filesystem"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"/path/to/your/project"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;


    &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;


    &lt;/span&gt;&lt;span class="nl"&gt;"test-generator"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;


      &lt;/span&gt;&lt;span class="nl"&gt;"command"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"node"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;


      &lt;/span&gt;&lt;span class="nl"&gt;"args"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"/path/to/your/mcp-test-generator/dist/index.js"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;


    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;


  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;


&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;


&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  5.4 Cursor MCP Config
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="err"&gt;//&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;.cursor/mcp.json&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;(project-level)&lt;/span&gt;&lt;span class="w"&gt;


&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;


  &lt;/span&gt;&lt;span class="nl"&gt;"mcpServers"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;


    &lt;/span&gt;&lt;span class="nl"&gt;"test-generator"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;


      &lt;/span&gt;&lt;span class="nl"&gt;"command"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"node"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;


      &lt;/span&gt;&lt;span class="nl"&gt;"args"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"./tools/mcp-test-generator/dist/index.js"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;


    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;


  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;


&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;


&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Part 6 — Anti-Hallucination Prompt Templates
&lt;/h2&gt;

&lt;p&gt;The root cause of AI hallucination in tests: AI invents method names, wrong mock structures, non-existent imports. These prompts eliminate that.&lt;/p&gt;

&lt;h3&gt;
  
  
  6.1 Cursor Cmd+K Prompt (Use This Exactly)
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;

Generate a unit &lt;span class="nb"&gt;test &lt;/span&gt;file &lt;span class="k"&gt;for &lt;/span&gt;this &lt;span class="o"&gt;[&lt;/span&gt;NestJS service / React component / Python class / Angular service / Laravel service].





Rules:


- Library: &lt;span class="o"&gt;[&lt;/span&gt;Jest / Vitest / pytest / Jest / Pest]


- Test only THIS file — no integration


- Mock ALL dependencies listed &lt;span class="k"&gt;in &lt;/span&gt;the constructor/props


- Follow AAA pattern with comments


- Minimum 4 &lt;span class="nb"&gt;test &lt;/span&gt;cases per public method


- Use ONLY methods/properties that exist &lt;span class="k"&gt;in &lt;/span&gt;this &lt;span class="nb"&gt;source &lt;/span&gt;file


- Do NOT import anything not shown &lt;span class="k"&gt;in &lt;/span&gt;the &lt;span class="nb"&gt;source&lt;/span&gt;


- Naming: &lt;span class="s2"&gt;"should [behavior] when [condition]"&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  6.2 Claude Prompt (For CLAUDE.md aware sessions)
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight markdown"&gt;&lt;code&gt;

Read [filename].&lt;span class="sb"&gt;


&lt;/span&gt;Extract:&lt;span class="sb"&gt;


&lt;/span&gt;&lt;span class="p"&gt;1.&lt;/span&gt; Class/function name&lt;span class="sb"&gt;


&lt;/span&gt;&lt;span class="p"&gt;2.&lt;/span&gt; All public methods with parameter types and return types&lt;span class="sb"&gt;


&lt;/span&gt;&lt;span class="p"&gt;3.&lt;/span&gt; All constructor dependencies (for mocking)&lt;span class="sb"&gt;





&lt;/span&gt;Then generate the unit test file following CLAUDE.md rules.&lt;span class="sb"&gt;


&lt;/span&gt;Do NOT assume any method exists unless you can see it in the source.&lt;span class="sb"&gt;


&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  6.3 Batch Test Generation Prompt
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;

&lt;span class="k"&gt;For&lt;/span&gt; &lt;span class="n"&gt;each&lt;/span&gt; &lt;span class="n"&gt;file&lt;/span&gt; &lt;span class="n"&gt;in&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;directory&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="n"&gt;generate&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="n"&gt;corresponding&lt;/span&gt; &lt;span class="mf"&gt;.&lt;/span&gt;&lt;span class="n"&gt;spec&lt;/span&gt;&lt;span class="mf"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ts&lt;/span&gt; &lt;span class="n"&gt;file&lt;/span&gt;&lt;span class="mf"&gt;.&lt;/span&gt;


&lt;span class="nc"&gt;Process&lt;/span&gt; &lt;span class="n"&gt;one&lt;/span&gt; &lt;span class="n"&gt;file&lt;/span&gt; &lt;span class="n"&gt;at&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="mf"&gt;.&lt;/span&gt;


&lt;span class="k"&gt;For&lt;/span&gt; &lt;span class="n"&gt;each&lt;/span&gt; &lt;span class="n"&gt;file&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;


  &lt;span class="mf"&gt;1.&lt;/span&gt; &lt;span class="nc"&gt;Read&lt;/span&gt; &lt;span class="n"&gt;the&lt;/span&gt; &lt;span class="n"&gt;source&lt;/span&gt;


  &lt;span class="mf"&gt;2.&lt;/span&gt; &lt;span class="k"&gt;List&lt;/span&gt; &lt;span class="n"&gt;the&lt;/span&gt; &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;methods&lt;/span&gt; &lt;span class="n"&gt;you&lt;/span&gt; &lt;span class="nf"&gt;found&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;confirm&lt;/span&gt; &lt;span class="n"&gt;before&lt;/span&gt; &lt;span class="n"&gt;generating&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;


  &lt;span class="mf"&gt;3.&lt;/span&gt; &lt;span class="nc"&gt;Generate&lt;/span&gt; &lt;span class="n"&gt;the&lt;/span&gt; &lt;span class="n"&gt;test&lt;/span&gt; &lt;span class="n"&gt;file&lt;/span&gt;


  &lt;span class="mf"&gt;4.&lt;/span&gt; &lt;span class="nc"&gt;Show&lt;/span&gt; &lt;span class="n"&gt;the&lt;/span&gt; &lt;span class="n"&gt;test&lt;/span&gt; &lt;span class="n"&gt;file&lt;/span&gt; &lt;span class="n"&gt;path&lt;/span&gt;





&lt;span class="k"&gt;Do&lt;/span&gt; &lt;span class="n"&gt;not&lt;/span&gt; &lt;span class="n"&gt;proceed&lt;/span&gt; &lt;span class="n"&gt;to&lt;/span&gt; &lt;span class="n"&gt;the&lt;/span&gt; &lt;span class="n"&gt;next&lt;/span&gt; &lt;span class="n"&gt;file&lt;/span&gt; &lt;span class="n"&gt;until&lt;/span&gt; &lt;span class="n"&gt;the&lt;/span&gt; &lt;span class="n"&gt;current&lt;/span&gt; &lt;span class="n"&gt;one&lt;/span&gt; &lt;span class="n"&gt;is&lt;/span&gt; &lt;span class="n"&gt;confirmed&lt;/span&gt;&lt;span class="mf"&gt;.&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Part 7 — Project Structure Convention
&lt;/h2&gt;

&lt;p&gt;All stacks follow the same proximity principle: &lt;strong&gt;test file lives next to source file&lt;/strong&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Node.js / NestJS / Angular
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight markdown"&gt;&lt;code&gt;

src/&lt;span class="sb"&gt;


&lt;/span&gt;  modules/&lt;span class="sb"&gt;


    users/


      users.service.ts


      users.service.spec.ts        ← unit test


      users.repository.ts


      users.repository.spec.ts     ← unit test


      users.guard.ts


      users.guard.spec.ts          ← unit test


&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  React
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

src/


  components/


    UserCard/


      UserCard.tsx


      UserCard.test.tsx            ← unit test


      UserCard.stories.tsx         ← storybook (optional)


  hooks/


    useUserData.ts


    useUserData.test.ts            ← unit test


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Python
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

app/


  services/


    user_service.py


tests/


  unit/


    services/


      test_user_service.py        ← mirrors app/ structure


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Laravel
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

app/


  Services/


    UserService.php


tests/


  Unit/


    Services/


      UserServiceTest.php         ← mirrors app/ structure


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Part 8 — CI Enforcement
&lt;/h2&gt;

&lt;p&gt;All of this means nothing without enforcement. The pipeline is the final gate.&lt;/p&gt;

&lt;h3&gt;
  
  
  GitHub Actions — Multi-stack parallel
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;

&lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Unit Tests&lt;/span&gt;





&lt;span class="na"&gt;on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;push&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;pull_request&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;





&lt;span class="na"&gt;jobs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;


  &lt;span class="na"&gt;nestjs-unit&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;


    &lt;span class="na"&gt;runs-on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;ubuntu-latest&lt;/span&gt;


    &lt;span class="na"&gt;steps&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;


      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;actions/checkout@v4&lt;/span&gt;


      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;actions/setup-node@v4&lt;/span&gt;


        &lt;span class="na"&gt;with&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;{&lt;/span&gt; &lt;span class="nv"&gt;node-version&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;20'&lt;/span&gt; &lt;span class="pi"&gt;}&lt;/span&gt;


      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;npm ci&lt;/span&gt;


      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;npm run test:unit -- --coverage --coverageThreshold='{"global":{"lines":80}}'&lt;/span&gt;





  &lt;span class="na"&gt;react-unit&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;


    &lt;span class="na"&gt;runs-on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;ubuntu-latest&lt;/span&gt;


    &lt;span class="na"&gt;steps&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;


      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;actions/checkout@v4&lt;/span&gt;


      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;actions/setup-node@v4&lt;/span&gt;


        &lt;span class="na"&gt;with&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;{&lt;/span&gt; &lt;span class="nv"&gt;node-version&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;20'&lt;/span&gt; &lt;span class="pi"&gt;}&lt;/span&gt;


      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;npm ci&lt;/span&gt;


      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;npx vitest run --coverage&lt;/span&gt;





  &lt;span class="na"&gt;python-unit&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;


    &lt;span class="na"&gt;runs-on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;ubuntu-latest&lt;/span&gt;


    &lt;span class="na"&gt;steps&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;


      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;actions/checkout@v4&lt;/span&gt;


      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;actions/setup-python@v5&lt;/span&gt;


        &lt;span class="na"&gt;with&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;{&lt;/span&gt; &lt;span class="nv"&gt;python-version&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;3.12'&lt;/span&gt; &lt;span class="pi"&gt;}&lt;/span&gt;


      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;pip install -r requirements-dev.txt&lt;/span&gt;


      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;pytest tests/unit/ --cov=app --cov-fail-under=80&lt;/span&gt;





  &lt;span class="na"&gt;laravel-unit&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;


    &lt;span class="na"&gt;runs-on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;ubuntu-latest&lt;/span&gt;


    &lt;span class="na"&gt;steps&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;


      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;actions/checkout@v4&lt;/span&gt;


      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;shivammathur/setup-php@v2&lt;/span&gt;


        &lt;span class="na"&gt;with&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;{&lt;/span&gt; &lt;span class="nv"&gt;php-version&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;8.3'&lt;/span&gt; &lt;span class="pi"&gt;}&lt;/span&gt;


      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;composer install&lt;/span&gt;


      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;./vendor/bin/pest --coverage --min=80&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Pre-commit Hook (Husky — Node stacks)
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="err"&gt;//&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;package.json&lt;/span&gt;&lt;span class="w"&gt;


&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;


  &lt;/span&gt;&lt;span class="nl"&gt;"lint-staged"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;


    &lt;/span&gt;&lt;span class="nl"&gt;"src/**/*.service.ts"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"jest --findRelatedTests --passWithNoTests"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;


    &lt;/span&gt;&lt;span class="nl"&gt;"src/**/*.tsx"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"vitest related --run"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;


  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;


&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;


&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Part 9 — Quick Start Checklist
&lt;/h2&gt;

&lt;h3&gt;
  
  
  New Project
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

□ Install test library (one per stack — see Part 1)


□ Configure jest.config.ts / vitest.config.ts / pytest.ini / pest.php


□ Create .cursor/rules/ directory with all rule files from Part 3


□ Create CLAUDE.md at project root from Part 4


□ Add coverage thresholds to config


□ Add pre-commit hooks (Husky for Node, pre-commit for Python)


□ Add CI workflow from Part 8


□ Create test factory files (one per major entity)


□ Write first failing test → implement → green → commit


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Existing Project
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

□ Add test library without touching existing code


□ Add .cursor/rules/ + CLAUDE.md


□ Run coverage on existing code → document current baseline


□ Pick 3 critical services → generate tests → set as new baseline


□ Add CI with threshold = current baseline (not ideal — current)


□ Raise threshold by 5% per sprint


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Appendix — Install Commands Per Stack
&lt;/h2&gt;

&lt;h3&gt;
  
  
  NestJS
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;

npm &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;--save-dev&lt;/span&gt; jest ts-jest @types/jest @nestjs/testing jest-mock-extended @golevelup/ts-jest


npx ts-jest config:init


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  React (Vite)
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;

npm &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;--save-dev&lt;/span&gt; vitest @vitest/coverage-v8 @testing-library/react @testing-library/user-event @testing-library/jest-dom jsdom


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Python
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;

pip &lt;span class="nb"&gt;install &lt;/span&gt;pytest pytest-cov pytest-mock pytest-asyncio factory-boy


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Angular
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;

ng add @angular-builders/jest


npm &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;--save-dev&lt;/span&gt; jest jest-preset-angular @types/jest


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Laravel
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;

composer require pestphp/pest pestphp/pest-plugin-laravel &lt;span class="nt"&gt;--dev&lt;/span&gt;


./vendor/bin/pest &lt;span class="nt"&gt;--init&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;p&gt;&lt;em&gt;Last updated: 2025 — verify library major versions before adopting&lt;/em&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>testing</category>
      <category>tutorial</category>
      <category>webdev</category>
    </item>
  </channel>
</rss>
