<?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>Thu, 09 Jul 2026 09:27:33 +0000</pubDate>
      <link>https://dev.to/bhaumik-viitor/unit-test-ai-guide-zero-hallucination-cross-stack-standard-35k3</link>
      <guid>https://dev.to/bhaumik-viitor/unit-test-ai-guide-zero-hallucination-cross-stack-standard-35k3</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Focus:&lt;/strong&gt; Unit Tests ONLY — no integration, no E2E&lt;br&gt;&lt;br&gt;
&lt;strong&gt;Stacks:&lt;/strong&gt; Node.js (NestJS/Express) · React.js · Python · Angular · Laravel&lt;br&gt;&lt;br&gt;
&lt;strong&gt;Goal:&lt;/strong&gt; AI generates unit tests consistently, deterministically, without hallucination&lt;br&gt;&lt;br&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;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Stack&lt;/th&gt;
&lt;th&gt;Library&lt;/th&gt;
&lt;th&gt;Why This One&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Node.js / NestJS / Express&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;Jest&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Native DI mocking, &lt;code&gt;@nestjs/testing&lt;/code&gt; built around it, widest ecosystem&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;React.js&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;Vitest&lt;/code&gt; + &lt;code&gt;@testing-library/react&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;Native Vite/ESM support, Jest-compatible API, 3–10x faster&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Python&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;pytest&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;De facto standard, fixture system eliminates boilerplate, best plugin ecosystem&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Angular&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;Jest&lt;/code&gt; (replace Karma)&lt;/td&gt;
&lt;td&gt;Karma is deprecated in Angular 17+; Jest is the official migration target&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Laravel&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;Pest&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Modern syntax, built on PHPUnit, higher signal-to-noise ratio&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&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;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Capability&lt;/th&gt;
&lt;th&gt;Cursor&lt;/th&gt;
&lt;th&gt;VS Code + Copilot&lt;/th&gt;
&lt;th&gt;WebStorm&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Project-level AI rules&lt;/td&gt;
&lt;td&gt;✅ &lt;code&gt;.cursor/rules/&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Codebase-aware context&lt;/td&gt;
&lt;td&gt;✅ &lt;code&gt;@codebase&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;Partial&lt;/td&gt;
&lt;td&gt;Partial&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Run terminal + read output&lt;/td&gt;
&lt;td&gt;✅ Composer&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Multi-file generation&lt;/td&gt;
&lt;td&gt;✅ Agent mode&lt;/td&gt;
&lt;td&gt;Limited&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Custom instructions per filetype&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;MCP server integration&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&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="nn"&gt;---&lt;/span&gt;
&lt;span class="na"&gt;description&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Global unit test rules — applies to all files in this project&lt;/span&gt;
&lt;span class="na"&gt;globs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;**/*.spec.ts"&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;**/*.test.ts"&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;**/*.spec.tsx"&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;**/*_test.py"&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;**/Test*.php"&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;
&lt;span class="na"&gt;alwaysApply&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
&lt;span class="nn"&gt;---&lt;/span&gt;

&lt;span class="gh"&gt;# Unit Test Contract — MUST FOLLOW, NO EXCEPTIONS&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="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;br&gt;
// Act — call the single function/method under test&lt;br&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="nn"&gt;---&lt;/span&gt;
&lt;span class="na"&gt;description&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;NestJS unit test rules&lt;/span&gt;
&lt;span class="na"&gt;globs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;src/**/*.service.ts"&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;src/**/*.guard.ts"&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;src/**/*.interceptor.ts"&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;src/**/*.pipe.ts"&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;
&lt;span class="nn"&gt;---&lt;/span&gt;

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

&lt;span class="gu"&gt;## Library: Jest + @nestjs/testing + jest-mock-extended&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;br&gt;
const module = await Test.createTestingModule({&lt;br&gt;
  providers: [&lt;br&gt;
    SubjectService,&lt;br&gt;
    { provide: DependencyService, useValue: mockDependency }&lt;br&gt;
  ]&lt;br&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;br&gt;
import { createMock } from '@golevelup/ts-jest';&lt;br&gt;
// OR&lt;br&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;br&gt;
const mockRepo = {&lt;br&gt;
  findOne: jest.fn(),&lt;br&gt;
  save: jest.fn(),&lt;br&gt;
  delete: jest.fn(),&lt;br&gt;
  findAll: jest.fn(),&lt;br&gt;
  update: jest.fn(),&lt;br&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;br&gt;
import { Test, TestingModule } from '@nestjs/testing';&lt;br&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="nn"&gt;---&lt;/span&gt;
&lt;span class="na"&gt;description&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;React unit test rules&lt;/span&gt;
&lt;span class="na"&gt;globs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;src/**/*.tsx"&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;src/**/*.component.tsx"&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;src/hooks/**/*.ts"&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;
&lt;span class="nn"&gt;---&lt;/span&gt;

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

&lt;span class="gu"&gt;## Library: Vitest + @testing-library/react + @testing-library/user-event&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;br&gt;
export default defineConfig({&lt;br&gt;
  test: {&lt;br&gt;
    environment: 'jsdom',&lt;br&gt;
    globals: true,&lt;br&gt;
    setupFiles: ['./src/test/setup.ts']&lt;br&gt;
  }&lt;br&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;br&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;br&gt;
import { render, screen } from '@testing-library/react';&lt;br&gt;
import userEvent from '@testing-library/user-event';&lt;br&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;br&gt;
const user = userEvent.setup();&lt;br&gt;
await user.click(button);&lt;br&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;br&gt;
import { renderHook, act } from '@testing-library/react';&lt;br&gt;
const { result } = renderHook(() =&amp;gt; useMyHook());&lt;br&gt;
act(() =&amp;gt; result.current.doSomething());&lt;br&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;
markdown&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="nn"&gt;---&lt;/span&gt;
&lt;span class="na"&gt;description&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Python unit test rules&lt;/span&gt;
&lt;span class="na"&gt;globs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;**/*.py"&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;!**/*migrations*"&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;
&lt;span class="nn"&gt;---&lt;/span&gt;

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

&lt;span class="gu"&gt;## Library: pytest + pytest-mock + factory-boy&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="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;br&gt;
    def &lt;strong&gt;init&lt;/strong&gt;(self, repo: UserRepository):&lt;br&gt;
        self.repo = repo&lt;/p&gt;
&lt;h1&gt;
  
  
  BAD — untestable
&lt;/h1&gt;

&lt;p&gt;class UserService:&lt;br&gt;
    def &lt;strong&gt;init&lt;/strong&gt;(self):&lt;br&gt;
        self.repo = UserRepository()  # can't mock this&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 — pytest-mock (mocker fixture)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;&lt;br&gt;
python&lt;br&gt;
def test_raises_when_user_not_found(mocker):&lt;br&gt;
    mock_repo = mocker.Mock()&lt;br&gt;
    mock_repo.find_by_id.return_value = None&lt;br&gt;
    service = UserService(mock_repo)&lt;br&gt;
    with pytest.raises(UserNotFoundException):&lt;br&gt;
        service.get_user("missing-id")&lt;br&gt;
&lt;/p&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;br&gt;
import pytest&lt;/p&gt;

&lt;p&gt;@pytest.mark.asyncio&lt;br&gt;
async def test_async_service(mocker):&lt;br&gt;
    mock_repo = mocker.AsyncMock()&lt;br&gt;
    ...&lt;br&gt;
&lt;/p&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;br&gt;
@pytest.fixture&lt;br&gt;
def user_service(mocker):&lt;br&gt;
    repo = mocker.Mock()&lt;br&gt;
    return UserService(repo), repo&lt;/p&gt;

&lt;p&gt;def test_get_user_happy_path(user_service):&lt;br&gt;
    service, repo = user_service&lt;br&gt;
    repo.find_by_id.return_value = User(id="1", email="&lt;a href="mailto:a@b.com"&gt;a@b.com&lt;/a&gt;")&lt;br&gt;
    result = service.get_user("1")&lt;br&gt;
    assert result.email == "&lt;a href="mailto:a@b.com"&gt;a@b.com&lt;/a&gt;"&lt;br&gt;
&lt;/p&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;
shell&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="nn"&gt;---&lt;/span&gt;
&lt;span class="na"&gt;description&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Angular unit test rules&lt;/span&gt;
&lt;span class="na"&gt;globs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;src/app/**/*.component.ts"&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;src/app/**/*.service.ts"&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;src/app/**/*.pipe.ts"&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;src/app/**/*.guard.ts"&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;
&lt;span class="nn"&gt;---&lt;/span&gt;

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

&lt;span class="gu"&gt;## Library: Jest (NOT Karma — Karma is deprecated Angular 17+)&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;br&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;br&gt;
await TestBed.configureTestingModule({&lt;br&gt;
  imports: [ComponentUnderTest],  // standalone components&lt;br&gt;
  providers: [&lt;br&gt;
    { provide: UserService, useValue: mockUserService }&lt;br&gt;
  ]&lt;br&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;br&gt;
const mockUserService = {&lt;br&gt;
  getUser: jest.fn(),&lt;br&gt;
  createUser: jest.fn(),&lt;br&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;br&gt;
fixture.detectChanges(); // trigger ngOnInit&lt;br&gt;
const button = fixture.debugElement.query(By.css('[data-testid="submit"]'));&lt;br&gt;
button.nativeElement.click();&lt;br&gt;
fixture.detectChanges();&lt;br&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;br&gt;
it('should transform date correctly', () =&amp;gt; {&lt;br&gt;
  const pipe = new DateFormatPipe();&lt;br&gt;
  expect(pipe.transform(new Date('2024-01-01'))).toBe('Jan 1, 2024');&lt;br&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;br&gt;
const guard = TestBed.inject(AuthGuard);&lt;br&gt;
const result = await guard.canActivate(mockRoute, mockState);&lt;br&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;
php&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="nn"&gt;---&lt;/span&gt;
&lt;span class="na"&gt;description&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Laravel unit test rules&lt;/span&gt;
&lt;span class="na"&gt;globs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;app/Services/**/*.php"&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;app/Models/**/*.php"&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;app/Http/Requests/**/*.php"&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;app/Actions/**/*.php"&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;
&lt;span class="nn"&gt;---&lt;/span&gt;

&lt;span class="gh"&gt;# Laravel Unit Test Rules&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="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;br&gt;
class UserService {&lt;br&gt;
    public function __construct(&lt;br&gt;
        private readonly UserRepositoryInterface $repo&lt;br&gt;
    ) {}&lt;br&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;br&gt;
it('throws exception when user not found', function () {&lt;br&gt;
    // Arrange&lt;br&gt;
    $repo = Mockery::mock(UserRepositoryInterface::class);&lt;br&gt;
    $repo-&amp;gt;shouldReceive('findById')-&amp;gt;once()-&amp;gt;andReturn(null);&lt;br&gt;
    $service = new UserService($repo);&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// 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;br&gt;
it('validates email format', function (string $email, bool $valid) {&lt;br&gt;
    expect(validateEmail($email))-&amp;gt;toBe($valid);&lt;br&gt;
})-&amp;gt;with([&lt;br&gt;
    ['&lt;a href="mailto:valid@email.com"&gt;valid@email.com&lt;/a&gt;', true],&lt;br&gt;
    ['notanemail', false],&lt;br&gt;
    ['', false],&lt;br&gt;
    ['@nodomain.com', false],&lt;br&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="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="gu"&gt;## Unit Test Rules — NON-NEGOTIABLE&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="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="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="gu"&gt;### Coverage target: 80% lines, 75% branches per module&lt;/span&gt;

&lt;span class="gu"&gt;## Project Structure Reference&lt;/span&gt;
src/
  modules/
    users/
      users.service.ts
      users.service.spec.ts   ← unit test lives here
      users.repository.ts
      users.repository.spec.ts
&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;Scope: E2E only — not relevant for unit tests&lt;/li&gt;
&lt;li&gt;Skip for this use case&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;Gives Claude access to project files&lt;/li&gt;
&lt;li&gt;Use in Claude Desktop to read source → generate tests&lt;/li&gt;
&lt;li&gt;Install: configured in &lt;code&gt;claude_desktop_config.json&lt;/code&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;Reads a source file&lt;/li&gt;
&lt;li&gt;Extracts function signatures + types&lt;/li&gt;
&lt;li&gt;Returns structured JSON to Claude&lt;/li&gt;
&lt;li&gt;Claude generates tests from structure, not guesswork
&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="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="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 plaintext"&gt;&lt;code&gt;Generate a unit test file for this [NestJS service / React component / Python class / Angular service / Laravel service].

Rules:
- Library: [Jest / Vitest / pytest / Jest / Pest]
- Test only THIS file — no integration
- Mock ALL dependencies listed in the constructor/props
- Follow AAA pattern with comments
- Minimum 4 test cases per public method
- Use ONLY methods/properties that exist in this source file
- Do NOT import anything not shown in the source
- Naming: "should [behavior] when [condition]"
&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 plaintext"&gt;&lt;code&gt;Read [filename].
Extract:
1. Class/function name
2. All public methods with parameter types and return types
3. All constructor dependencies (for mocking)

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 plaintext"&gt;&lt;code&gt;For each file in [directory], generate a corresponding .spec.ts file.
Process one file at a time.
For each file:
  1. Read the source
  2. List the public methods you found (confirm before generating)
  3. Generate the test file
  4. Show the test file path

Do not proceed to the next file until the current one is confirmed.
&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 plaintext"&gt;&lt;code&gt;src/
  modules/
    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;/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="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>unittests</category>
      <category>testing</category>
      <category>cursor</category>
      <category>pytest</category>
    </item>
    <item>
      <title>Can You Vibe Code a Laravel App in 2026?</title>
      <dc:creator>Bhaumik</dc:creator>
      <pubDate>Mon, 29 Jun 2026 07:06:13 +0000</pubDate>
      <link>https://dev.to/bhaumik-viitor/can-you-vibe-code-a-laravel-app-in-2026-32fe</link>
      <guid>https://dev.to/bhaumik-viitor/can-you-vibe-code-a-laravel-app-in-2026-32fe</guid>
      <description>&lt;p&gt;Vibe coding went mainstream in 2025. You describe what you want in plain English, an AI builds it, and you refine by talking instead of typing. The catch for our world is simple: almost every vibe coding tool ships JavaScript or React, not Laravel. So the question Laravel developers keep asking is fair. Can you actually vibe code a real, shippable Laravel app in 2026?&lt;/p&gt;

&lt;p&gt;The short answer is yes, but only if the tool understands Laravel from the inside.&lt;/p&gt;

&lt;h2&gt;
  
  
  What vibe coding actually means for Laravel
&lt;/h2&gt;

&lt;p&gt;Vibe coding is not autocomplete. Autocomplete finishes the line you are already writing. Vibe coding builds the thing you describe: models, migrations, controllers, routes, CRUD, auth, and the views to go with them. You stay in the loop by reviewing and prompting, not by hand writing every scaffold.&lt;/p&gt;

&lt;p&gt;For a Laravel developer, the difference between a generic builder and a Laravel-native one is enormous. A generic tool can produce PHP, but it does not produce idiomatic Eloquent relationships, convention-correct migrations, Blade or Livewire views, or routes structured the way Laravel expects. You end up reworking the output, which erases the time the AI was supposed to save. If you want a deeper look at the category, our roundup of &lt;a href="https://laracopilot.com/blog/vibe-coding-tools/" rel="noopener noreferrer"&gt;vibe coding tools&lt;/a&gt; breaks down where each approach fits.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why most AI tools still miss Laravel
&lt;/h2&gt;

&lt;p&gt;The AI coding wave was built for JavaScript, TypeScript, and Python first. That left more than two million Laravel developers working around tools that treat PHP as an afterthought. The result is predictable: prompts that should produce a clean resource controller instead produce something close, but not Laravel. Close is expensive. Close means a code review, a refactor, and a quiet decision to go back to writing the boilerplate by hand.&lt;/p&gt;

&lt;p&gt;This is the gap that matters in 2026. Laravel is one of the largest frameworks in the world, the ecosystem is maturing fast around Laravel 13+ and PHP 8.3+, and the developers shipping on it want the same describe-it-and-build-it experience everyone else got two years ago. They just want it to actually run on a Laravel stack they can own.&lt;/p&gt;

&lt;h2&gt;
  
  
  How LaraCopilot approaches it
&lt;/h2&gt;

&lt;p&gt;LaraCopilot is built specifically for Laravel, so vibe coding behaves the way a Laravel developer would expect. You describe the application in plain English and it generates production-ready Laravel apps: Eloquent models, migrations, controllers, full CRUD, authentication flows, and REST or GraphQL endpoints. Output is PSR-compliant and Laravel Pint formatted by default, so it reads like code a senior engineer on your team would write, not code you have to translate. You pick the UI layer too, whether that is Blade, Livewire, or Inertia with React or Vue.&lt;/p&gt;

&lt;p&gt;If you are starting from a description rather than a blank artisan command, our guide on using a &lt;a href="https://laracopilot.com/blog/laravel-ai-code-generators/" rel="noopener noreferrer"&gt;Laravel AI code generator&lt;/a&gt; walks through how the generation flow works step by step, from prompt to running app.&lt;/p&gt;

&lt;h2&gt;
  
  
  A real example
&lt;/h2&gt;

&lt;p&gt;A founder used this exact flow to build a local marketplace with authentication, billing, and a dashboard in under two hours. The same scope had previously been estimated at three weeks of manual Laravel work. The app went live and onboarded more than two hundred users immediately. That is the practical promise of vibe coding for Laravel: not a toy prototype, but a production-ready app you can ship and own.&lt;/p&gt;

&lt;p&gt;The proof shows up at scale too. More than 6,000 developers are now building this way, with over 2.4 million lines of Laravel generated and 98 percent customer satisfaction, all without a dollar of paid acquisition. For a closer look at speed, see how teams &lt;a href="https://laracopilot.com/blog/build-laravel-apps-in-minutes-using-ai/" rel="noopener noreferrer"&gt;build Laravel apps in minutes using AI&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  So, can you vibe code Laravel in 2026?
&lt;/h2&gt;

&lt;p&gt;Yes, when the tool is Laravel-native. Vibe coding only works for our stack when the AI generates the conventions Laravel runs on, not a generic approximation you have to fix. The boilerplate you write on every project, the CRUD, the auth, the APIs, is exactly the part worth handing off, so you can spend your time on business logic and problem solving.&lt;/p&gt;

&lt;p&gt;Meet LaraCopilot, your AI full-stack assistant built for Laravel developers. &lt;a href="https://laracopilot.com" rel="noopener noreferrer"&gt;Try LaraCopilot Now&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>laravel</category>
      <category>vibecoding</category>
      <category>ai</category>
    </item>
    <item>
      <title>Unit Test AI Guide — Zero Hallucination, Cross-Stack Standard</title>
      <dc:creator>Bhaumik</dc:creator>
      <pubDate>Fri, 26 Jun 2026 05:27:22 +0000</pubDate>
      <link>https://dev.to/bhaumik-viitor/unit-test-ai-guide-zero-hallucination-cross-stack-standard-3den</link>
      <guid>https://dev.to/bhaumik-viitor/unit-test-ai-guide-zero-hallucination-cross-stack-standard-3den</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Focus:&lt;/strong&gt; Unit Tests ONLY — no integration, no E2E&lt;br&gt;&lt;br&gt;
&lt;strong&gt;Stacks:&lt;/strong&gt; Node.js (NestJS/Express) · React.js · Python · Angular · Laravel&lt;br&gt;&lt;br&gt;
&lt;strong&gt;Goal:&lt;/strong&gt; AI generates unit tests consistently, deterministically, without hallucination&lt;br&gt;&lt;br&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;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Stack&lt;/th&gt;
&lt;th&gt;Library&lt;/th&gt;
&lt;th&gt;Why This One&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Node.js / NestJS / Express&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;Jest&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Native DI mocking, &lt;code&gt;@nestjs/testing&lt;/code&gt; built around it, widest ecosystem&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;React.js&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;Vitest&lt;/code&gt; + &lt;code&gt;@testing-library/react&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;Native Vite/ESM support, Jest-compatible API, 3–10x faster&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Python&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;pytest&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;De facto standard, fixture system eliminates boilerplate, best plugin ecosystem&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Angular&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;Jest&lt;/code&gt; (replace Karma)&lt;/td&gt;
&lt;td&gt;Karma is deprecated in Angular 17+; Jest is the official migration target&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Laravel&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;Pest&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Modern syntax, built on PHPUnit, higher signal-to-noise ratio&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&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;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Capability&lt;/th&gt;
&lt;th&gt;Cursor&lt;/th&gt;
&lt;th&gt;VS Code + Copilot&lt;/th&gt;
&lt;th&gt;WebStorm&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Project-level AI rules&lt;/td&gt;
&lt;td&gt;✅ &lt;code&gt;.cursor/rules/&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Codebase-aware context&lt;/td&gt;
&lt;td&gt;✅ &lt;code&gt;@codebase&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;Partial&lt;/td&gt;
&lt;td&gt;Partial&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Run terminal + read output&lt;/td&gt;
&lt;td&gt;✅ Composer&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Multi-file generation&lt;/td&gt;
&lt;td&gt;✅ Agent mode&lt;/td&gt;
&lt;td&gt;Limited&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Custom instructions per filetype&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;MCP server integration&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&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="nn"&gt;---&lt;/span&gt;
&lt;span class="na"&gt;description&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Global unit test rules — applies to all files in this project&lt;/span&gt;
&lt;span class="na"&gt;globs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;**/*.spec.ts"&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;**/*.test.ts"&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;**/*.spec.tsx"&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;**/*_test.py"&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;**/Test*.php"&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;
&lt;span class="na"&gt;alwaysApply&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
&lt;span class="nn"&gt;---&lt;/span&gt;

&lt;span class="gh"&gt;# Unit Test Contract — MUST FOLLOW, NO EXCEPTIONS&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="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;br&gt;
// Act — call the single function/method under test&lt;br&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="nn"&gt;---&lt;/span&gt;
&lt;span class="na"&gt;description&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;NestJS unit test rules&lt;/span&gt;
&lt;span class="na"&gt;globs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;src/**/*.service.ts"&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;src/**/*.guard.ts"&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;src/**/*.interceptor.ts"&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;src/**/*.pipe.ts"&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;
&lt;span class="nn"&gt;---&lt;/span&gt;

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

&lt;span class="gu"&gt;## Library: Jest + @nestjs/testing + jest-mock-extended&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;br&gt;
const module = await Test.createTestingModule({&lt;br&gt;
  providers: [&lt;br&gt;
    SubjectService,&lt;br&gt;
    { provide: DependencyService, useValue: mockDependency }&lt;br&gt;
  ]&lt;br&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;br&gt;
import { createMock } from '@golevelup/ts-jest';&lt;br&gt;
// OR&lt;br&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;br&gt;
const mockRepo = {&lt;br&gt;
  findOne: jest.fn(),&lt;br&gt;
  save: jest.fn(),&lt;br&gt;
  delete: jest.fn(),&lt;br&gt;
  findAll: jest.fn(),&lt;br&gt;
  update: jest.fn(),&lt;br&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;br&gt;
import { Test, TestingModule } from '@nestjs/testing';&lt;br&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="nn"&gt;---&lt;/span&gt;
&lt;span class="na"&gt;description&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;React unit test rules&lt;/span&gt;
&lt;span class="na"&gt;globs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;src/**/*.tsx"&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;src/**/*.component.tsx"&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;src/hooks/**/*.ts"&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;
&lt;span class="nn"&gt;---&lt;/span&gt;

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

&lt;span class="gu"&gt;## Library: Vitest + @testing-library/react + @testing-library/user-event&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;br&gt;
export default defineConfig({&lt;br&gt;
  test: {&lt;br&gt;
    environment: 'jsdom',&lt;br&gt;
    globals: true,&lt;br&gt;
    setupFiles: ['./src/test/setup.ts']&lt;br&gt;
  }&lt;br&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;br&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;br&gt;
import { render, screen } from '@testing-library/react';&lt;br&gt;
import userEvent from '@testing-library/user-event';&lt;br&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;br&gt;
const user = userEvent.setup();&lt;br&gt;
await user.click(button);&lt;br&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;br&gt;
import { renderHook, act } from '@testing-library/react';&lt;br&gt;
const { result } = renderHook(() =&amp;gt; useMyHook());&lt;br&gt;
act(() =&amp;gt; result.current.doSomething());&lt;br&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;
markdown&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="nn"&gt;---&lt;/span&gt;
&lt;span class="na"&gt;description&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Python unit test rules&lt;/span&gt;
&lt;span class="na"&gt;globs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;**/*.py"&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;!**/*migrations*"&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;
&lt;span class="nn"&gt;---&lt;/span&gt;

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

&lt;span class="gu"&gt;## Library: pytest + pytest-mock + factory-boy&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="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;br&gt;
    def &lt;strong&gt;init&lt;/strong&gt;(self, repo: UserRepository):&lt;br&gt;
        self.repo = repo&lt;/p&gt;
&lt;h1&gt;
  
  
  BAD — untestable
&lt;/h1&gt;

&lt;p&gt;class UserService:&lt;br&gt;
    def &lt;strong&gt;init&lt;/strong&gt;(self):&lt;br&gt;
        self.repo = UserRepository()  # can't mock this&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 — pytest-mock (mocker fixture)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;&lt;br&gt;
python&lt;br&gt;
def test_raises_when_user_not_found(mocker):&lt;br&gt;
    mock_repo = mocker.Mock()&lt;br&gt;
    mock_repo.find_by_id.return_value = None&lt;br&gt;
    service = UserService(mock_repo)&lt;br&gt;
    with pytest.raises(UserNotFoundException):&lt;br&gt;
        service.get_user("missing-id")&lt;br&gt;
&lt;/p&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;br&gt;
import pytest&lt;/p&gt;

&lt;p&gt;@pytest.mark.asyncio&lt;br&gt;
async def test_async_service(mocker):&lt;br&gt;
    mock_repo = mocker.AsyncMock()&lt;br&gt;
    ...&lt;br&gt;
&lt;/p&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;br&gt;
@pytest.fixture&lt;br&gt;
def user_service(mocker):&lt;br&gt;
    repo = mocker.Mock()&lt;br&gt;
    return UserService(repo), repo&lt;/p&gt;

&lt;p&gt;def test_get_user_happy_path(user_service):&lt;br&gt;
    service, repo = user_service&lt;br&gt;
    repo.find_by_id.return_value = User(id="1", email="&lt;a href="mailto:a@b.com"&gt;a@b.com&lt;/a&gt;")&lt;br&gt;
    result = service.get_user("1")&lt;br&gt;
    assert result.email == "&lt;a href="mailto:a@b.com"&gt;a@b.com&lt;/a&gt;"&lt;br&gt;
&lt;/p&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;
shell&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="nn"&gt;---&lt;/span&gt;
&lt;span class="na"&gt;description&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Angular unit test rules&lt;/span&gt;
&lt;span class="na"&gt;globs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;src/app/**/*.component.ts"&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;src/app/**/*.service.ts"&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;src/app/**/*.pipe.ts"&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;src/app/**/*.guard.ts"&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;
&lt;span class="nn"&gt;---&lt;/span&gt;

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

&lt;span class="gu"&gt;## Library: Jest (NOT Karma — Karma is deprecated Angular 17+)&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;br&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;br&gt;
await TestBed.configureTestingModule({&lt;br&gt;
  imports: [ComponentUnderTest],  // standalone components&lt;br&gt;
  providers: [&lt;br&gt;
    { provide: UserService, useValue: mockUserService }&lt;br&gt;
  ]&lt;br&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;br&gt;
const mockUserService = {&lt;br&gt;
  getUser: jest.fn(),&lt;br&gt;
  createUser: jest.fn(),&lt;br&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;br&gt;
fixture.detectChanges(); // trigger ngOnInit&lt;br&gt;
const button = fixture.debugElement.query(By.css('[data-testid="submit"]'));&lt;br&gt;
button.nativeElement.click();&lt;br&gt;
fixture.detectChanges();&lt;br&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;br&gt;
it('should transform date correctly', () =&amp;gt; {&lt;br&gt;
  const pipe = new DateFormatPipe();&lt;br&gt;
  expect(pipe.transform(new Date('2024-01-01'))).toBe('Jan 1, 2024');&lt;br&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;br&gt;
const guard = TestBed.inject(AuthGuard);&lt;br&gt;
const result = await guard.canActivate(mockRoute, mockState);&lt;br&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;
php&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="nn"&gt;---&lt;/span&gt;
&lt;span class="na"&gt;description&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Laravel unit test rules&lt;/span&gt;
&lt;span class="na"&gt;globs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;app/Services/**/*.php"&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;app/Models/**/*.php"&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;app/Http/Requests/**/*.php"&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;app/Actions/**/*.php"&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;
&lt;span class="nn"&gt;---&lt;/span&gt;

&lt;span class="gh"&gt;# Laravel Unit Test Rules&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="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;br&gt;
class UserService {&lt;br&gt;
    public function __construct(&lt;br&gt;
        private readonly UserRepositoryInterface $repo&lt;br&gt;
    ) {}&lt;br&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;br&gt;
it('throws exception when user not found', function () {&lt;br&gt;
    // Arrange&lt;br&gt;
    $repo = Mockery::mock(UserRepositoryInterface::class);&lt;br&gt;
    $repo-&amp;gt;shouldReceive('findById')-&amp;gt;once()-&amp;gt;andReturn(null);&lt;br&gt;
    $service = new UserService($repo);&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// 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;br&gt;
it('validates email format', function (string $email, bool $valid) {&lt;br&gt;
    expect(validateEmail($email))-&amp;gt;toBe($valid);&lt;br&gt;
})-&amp;gt;with([&lt;br&gt;
    ['&lt;a href="mailto:valid@email.com"&gt;valid@email.com&lt;/a&gt;', true],&lt;br&gt;
    ['notanemail', false],&lt;br&gt;
    ['', false],&lt;br&gt;
    ['@nodomain.com', false],&lt;br&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="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="gu"&gt;## Unit Test Rules — NON-NEGOTIABLE&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="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="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="gu"&gt;### Coverage target: 80% lines, 75% branches per module&lt;/span&gt;

&lt;span class="gu"&gt;## Project Structure Reference&lt;/span&gt;
src/
  modules/
    users/
      users.service.ts
      users.service.spec.ts   ← unit test lives here
      users.repository.ts
      users.repository.spec.ts
&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;Scope: E2E only — not relevant for unit tests&lt;/li&gt;
&lt;li&gt;Skip for this use case&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;Gives Claude access to project files&lt;/li&gt;
&lt;li&gt;Use in Claude Desktop to read source → generate tests&lt;/li&gt;
&lt;li&gt;Install: configured in &lt;code&gt;claude_desktop_config.json&lt;/code&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;Reads a source file&lt;/li&gt;
&lt;li&gt;Extracts function signatures + types&lt;/li&gt;
&lt;li&gt;Returns structured JSON to Claude&lt;/li&gt;
&lt;li&gt;Claude generates tests from structure, not guesswork
&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="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="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 plaintext"&gt;&lt;code&gt;Generate a unit test file for this [NestJS service / React component / Python class / Angular service / Laravel service].

Rules:
- Library: [Jest / Vitest / pytest / Jest / Pest]
- Test only THIS file — no integration
- Mock ALL dependencies listed in the constructor/props
- Follow AAA pattern with comments
- Minimum 4 test cases per public method
- Use ONLY methods/properties that exist in this source file
- Do NOT import anything not shown in the source
- Naming: "should [behavior] when [condition]"
&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 plaintext"&gt;&lt;code&gt;Read [filename].
Extract:
1. Class/function name
2. All public methods with parameter types and return types
3. All constructor dependencies (for mocking)

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 plaintext"&gt;&lt;code&gt;For each file in [directory], generate a corresponding .spec.ts file.
Process one file at a time.
For each file:
  1. Read the source
  2. List the public methods you found (confirm before generating)
  3. Generate the test file
  4. Show the test file path

Do not proceed to the next file until the current one is confirmed.
&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 plaintext"&gt;&lt;code&gt;src/
  modules/
    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;/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="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>unittests</category>
      <category>testing</category>
      <category>cursor</category>
      <category>pytest</category>
    </item>
    <item>
      <title>Unit Test AI Guide — Zero Hallucination, Cross-Stack Standard</title>
      <dc:creator>Bhaumik</dc:creator>
      <pubDate>Fri, 26 Jun 2026 05:03:03 +0000</pubDate>
      <link>https://dev.to/bhaumik-viitor/unit-test-ai-guide-zero-hallucination-cross-stack-standard-3fk4</link>
      <guid>https://dev.to/bhaumik-viitor/unit-test-ai-guide-zero-hallucination-cross-stack-standard-3fk4</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Focus:&lt;/strong&gt; Unit Tests ONLY — no integration, no E2E&lt;br&gt;&lt;br&gt;
&lt;strong&gt;Stacks:&lt;/strong&gt; Node.js (NestJS/Express) · React.js · Python · Angular · Laravel&lt;br&gt;&lt;br&gt;
&lt;strong&gt;Goal:&lt;/strong&gt; AI generates unit tests consistently, deterministically, without hallucination&lt;br&gt;&lt;br&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;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Stack&lt;/th&gt;
&lt;th&gt;Library&lt;/th&gt;
&lt;th&gt;Why This One&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Node.js / NestJS / Express&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;Jest&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Native DI mocking, &lt;code&gt;@nestjs/testing&lt;/code&gt; built around it, widest ecosystem&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;React.js&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;Vitest&lt;/code&gt; + &lt;code&gt;@testing-library/react&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;Native Vite/ESM support, Jest-compatible API, 3–10x faster&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Python&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;pytest&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;De facto standard, fixture system eliminates boilerplate, best plugin ecosystem&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Angular&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;Jest&lt;/code&gt; (replace Karma)&lt;/td&gt;
&lt;td&gt;Karma is deprecated in Angular 17+; Jest is the official migration target&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Laravel&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;Pest&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Modern syntax, built on PHPUnit, higher signal-to-noise ratio&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&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;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Capability&lt;/th&gt;
&lt;th&gt;Cursor&lt;/th&gt;
&lt;th&gt;VS Code + Copilot&lt;/th&gt;
&lt;th&gt;WebStorm&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Project-level AI rules&lt;/td&gt;
&lt;td&gt;✅ &lt;code&gt;.cursor/rules/&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Codebase-aware context&lt;/td&gt;
&lt;td&gt;✅ &lt;code&gt;@codebase&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;Partial&lt;/td&gt;
&lt;td&gt;Partial&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Run terminal + read output&lt;/td&gt;
&lt;td&gt;✅ Composer&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Multi-file generation&lt;/td&gt;
&lt;td&gt;✅ Agent mode&lt;/td&gt;
&lt;td&gt;Limited&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Custom instructions per filetype&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;MCP server integration&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&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="nn"&gt;---&lt;/span&gt;
&lt;span class="na"&gt;description&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Global unit test rules — applies to all files in this project&lt;/span&gt;
&lt;span class="na"&gt;globs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;**/*.spec.ts"&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;**/*.test.ts"&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;**/*.spec.tsx"&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;**/*_test.py"&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;**/Test*.php"&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;
&lt;span class="na"&gt;alwaysApply&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
&lt;span class="nn"&gt;---&lt;/span&gt;

&lt;span class="gh"&gt;# Unit Test Contract — MUST FOLLOW, NO EXCEPTIONS&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="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;br&gt;
// Act — call the single function/method under test&lt;br&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="nn"&gt;---&lt;/span&gt;
&lt;span class="na"&gt;description&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;NestJS unit test rules&lt;/span&gt;
&lt;span class="na"&gt;globs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;src/**/*.service.ts"&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;src/**/*.guard.ts"&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;src/**/*.interceptor.ts"&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;src/**/*.pipe.ts"&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;
&lt;span class="nn"&gt;---&lt;/span&gt;

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

&lt;span class="gu"&gt;## Library: Jest + @nestjs/testing + jest-mock-extended&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;br&gt;
const module = await Test.createTestingModule({&lt;br&gt;
  providers: [&lt;br&gt;
    SubjectService,&lt;br&gt;
    { provide: DependencyService, useValue: mockDependency }&lt;br&gt;
  ]&lt;br&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;br&gt;
import { createMock } from '@golevelup/ts-jest';&lt;br&gt;
// OR&lt;br&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;br&gt;
const mockRepo = {&lt;br&gt;
  findOne: jest.fn(),&lt;br&gt;
  save: jest.fn(),&lt;br&gt;
  delete: jest.fn(),&lt;br&gt;
  findAll: jest.fn(),&lt;br&gt;
  update: jest.fn(),&lt;br&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;br&gt;
import { Test, TestingModule } from '@nestjs/testing';&lt;br&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="nn"&gt;---&lt;/span&gt;
&lt;span class="na"&gt;description&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;React unit test rules&lt;/span&gt;
&lt;span class="na"&gt;globs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;src/**/*.tsx"&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;src/**/*.component.tsx"&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;src/hooks/**/*.ts"&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;
&lt;span class="nn"&gt;---&lt;/span&gt;

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

&lt;span class="gu"&gt;## Library: Vitest + @testing-library/react + @testing-library/user-event&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;br&gt;
export default defineConfig({&lt;br&gt;
  test: {&lt;br&gt;
    environment: 'jsdom',&lt;br&gt;
    globals: true,&lt;br&gt;
    setupFiles: ['./src/test/setup.ts']&lt;br&gt;
  }&lt;br&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;br&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;br&gt;
import { render, screen } from '@testing-library/react';&lt;br&gt;
import userEvent from '@testing-library/user-event';&lt;br&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;br&gt;
const user = userEvent.setup();&lt;br&gt;
await user.click(button);&lt;br&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;br&gt;
import { renderHook, act } from '@testing-library/react';&lt;br&gt;
const { result } = renderHook(() =&amp;gt; useMyHook());&lt;br&gt;
act(() =&amp;gt; result.current.doSomething());&lt;br&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;
markdown&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="nn"&gt;---&lt;/span&gt;
&lt;span class="na"&gt;description&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Python unit test rules&lt;/span&gt;
&lt;span class="na"&gt;globs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;**/*.py"&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;!**/*migrations*"&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;
&lt;span class="nn"&gt;---&lt;/span&gt;

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

&lt;span class="gu"&gt;## Library: pytest + pytest-mock + factory-boy&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="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;br&gt;
    def &lt;strong&gt;init&lt;/strong&gt;(self, repo: UserRepository):&lt;br&gt;
        self.repo = repo&lt;/p&gt;
&lt;h1&gt;
  
  
  BAD — untestable
&lt;/h1&gt;

&lt;p&gt;class UserService:&lt;br&gt;
    def &lt;strong&gt;init&lt;/strong&gt;(self):&lt;br&gt;
        self.repo = UserRepository()  # can't mock this&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 — pytest-mock (mocker fixture)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;&lt;br&gt;
python&lt;br&gt;
def test_raises_when_user_not_found(mocker):&lt;br&gt;
    mock_repo = mocker.Mock()&lt;br&gt;
    mock_repo.find_by_id.return_value = None&lt;br&gt;
    service = UserService(mock_repo)&lt;br&gt;
    with pytest.raises(UserNotFoundException):&lt;br&gt;
        service.get_user("missing-id")&lt;br&gt;
&lt;/p&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;br&gt;
import pytest&lt;/p&gt;

&lt;p&gt;@pytest.mark.asyncio&lt;br&gt;
async def test_async_service(mocker):&lt;br&gt;
    mock_repo = mocker.AsyncMock()&lt;br&gt;
    ...&lt;br&gt;
&lt;/p&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;br&gt;
@pytest.fixture&lt;br&gt;
def user_service(mocker):&lt;br&gt;
    repo = mocker.Mock()&lt;br&gt;
    return UserService(repo), repo&lt;/p&gt;

&lt;p&gt;def test_get_user_happy_path(user_service):&lt;br&gt;
    service, repo = user_service&lt;br&gt;
    repo.find_by_id.return_value = User(id="1", email="&lt;a href="mailto:a@b.com"&gt;a@b.com&lt;/a&gt;")&lt;br&gt;
    result = service.get_user("1")&lt;br&gt;
    assert result.email == "&lt;a href="mailto:a@b.com"&gt;a@b.com&lt;/a&gt;"&lt;br&gt;
&lt;/p&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;
shell&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="nn"&gt;---&lt;/span&gt;
&lt;span class="na"&gt;description&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Angular unit test rules&lt;/span&gt;
&lt;span class="na"&gt;globs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;src/app/**/*.component.ts"&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;src/app/**/*.service.ts"&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;src/app/**/*.pipe.ts"&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;src/app/**/*.guard.ts"&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;
&lt;span class="nn"&gt;---&lt;/span&gt;

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

&lt;span class="gu"&gt;## Library: Jest (NOT Karma — Karma is deprecated Angular 17+)&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;br&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;br&gt;
await TestBed.configureTestingModule({&lt;br&gt;
  imports: [ComponentUnderTest],  // standalone components&lt;br&gt;
  providers: [&lt;br&gt;
    { provide: UserService, useValue: mockUserService }&lt;br&gt;
  ]&lt;br&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;br&gt;
const mockUserService = {&lt;br&gt;
  getUser: jest.fn(),&lt;br&gt;
  createUser: jest.fn(),&lt;br&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;br&gt;
fixture.detectChanges(); // trigger ngOnInit&lt;br&gt;
const button = fixture.debugElement.query(By.css('[data-testid="submit"]'));&lt;br&gt;
button.nativeElement.click();&lt;br&gt;
fixture.detectChanges();&lt;br&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;br&gt;
it('should transform date correctly', () =&amp;gt; {&lt;br&gt;
  const pipe = new DateFormatPipe();&lt;br&gt;
  expect(pipe.transform(new Date('2024-01-01'))).toBe('Jan 1, 2024');&lt;br&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;br&gt;
const guard = TestBed.inject(AuthGuard);&lt;br&gt;
const result = await guard.canActivate(mockRoute, mockState);&lt;br&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;
php&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="nn"&gt;---&lt;/span&gt;
&lt;span class="na"&gt;description&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Laravel unit test rules&lt;/span&gt;
&lt;span class="na"&gt;globs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;app/Services/**/*.php"&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;app/Models/**/*.php"&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;app/Http/Requests/**/*.php"&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;app/Actions/**/*.php"&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;
&lt;span class="nn"&gt;---&lt;/span&gt;

&lt;span class="gh"&gt;# Laravel Unit Test Rules&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="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;br&gt;
class UserService {&lt;br&gt;
    public function __construct(&lt;br&gt;
        private readonly UserRepositoryInterface $repo&lt;br&gt;
    ) {}&lt;br&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;br&gt;
it('throws exception when user not found', function () {&lt;br&gt;
    // Arrange&lt;br&gt;
    $repo = Mockery::mock(UserRepositoryInterface::class);&lt;br&gt;
    $repo-&amp;gt;shouldReceive('findById')-&amp;gt;once()-&amp;gt;andReturn(null);&lt;br&gt;
    $service = new UserService($repo);&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// 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;br&gt;
it('validates email format', function (string $email, bool $valid) {&lt;br&gt;
    expect(validateEmail($email))-&amp;gt;toBe($valid);&lt;br&gt;
})-&amp;gt;with([&lt;br&gt;
    ['&lt;a href="mailto:valid@email.com"&gt;valid@email.com&lt;/a&gt;', true],&lt;br&gt;
    ['notanemail', false],&lt;br&gt;
    ['', false],&lt;br&gt;
    ['@nodomain.com', false],&lt;br&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="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="gu"&gt;## Unit Test Rules — NON-NEGOTIABLE&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="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="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="gu"&gt;### Coverage target: 80% lines, 75% branches per module&lt;/span&gt;

&lt;span class="gu"&gt;## Project Structure Reference&lt;/span&gt;
src/
  modules/
    users/
      users.service.ts
      users.service.spec.ts   ← unit test lives here
      users.repository.ts
      users.repository.spec.ts
&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;Scope: E2E only — not relevant for unit tests&lt;/li&gt;
&lt;li&gt;Skip for this use case&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;Gives Claude access to project files&lt;/li&gt;
&lt;li&gt;Use in Claude Desktop to read source → generate tests&lt;/li&gt;
&lt;li&gt;Install: configured in &lt;code&gt;claude_desktop_config.json&lt;/code&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;Reads a source file&lt;/li&gt;
&lt;li&gt;Extracts function signatures + types&lt;/li&gt;
&lt;li&gt;Returns structured JSON to Claude&lt;/li&gt;
&lt;li&gt;Claude generates tests from structure, not guesswork
&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="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="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 plaintext"&gt;&lt;code&gt;Generate a unit test file for this [NestJS service / React component / Python class / Angular service / Laravel service].

Rules:
- Library: [Jest / Vitest / pytest / Jest / Pest]
- Test only THIS file — no integration
- Mock ALL dependencies listed in the constructor/props
- Follow AAA pattern with comments
- Minimum 4 test cases per public method
- Use ONLY methods/properties that exist in this source file
- Do NOT import anything not shown in the source
- Naming: "should [behavior] when [condition]"
&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 plaintext"&gt;&lt;code&gt;Read [filename].
Extract:
1. Class/function name
2. All public methods with parameter types and return types
3. All constructor dependencies (for mocking)

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 plaintext"&gt;&lt;code&gt;For each file in [directory], generate a corresponding .spec.ts file.
Process one file at a time.
For each file:
  1. Read the source
  2. List the public methods you found (confirm before generating)
  3. Generate the test file
  4. Show the test file path

Do not proceed to the next file until the current one is confirmed.
&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 plaintext"&gt;&lt;code&gt;src/
  modules/
    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;/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="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>unittests</category>
      <category>testing</category>
      <category>cursor</category>
      <category>pytest</category>
    </item>
    <item>
      <title>Unit Test AI Guide — Zero Hallucination, Cross-Stack Standard</title>
      <dc:creator>Bhaumik</dc:creator>
      <pubDate>Wed, 24 Jun 2026 07:04:19 +0000</pubDate>
      <link>https://dev.to/bhaumik-viitor/unit-test-ai-guide-zero-hallucination-cross-stack-standard-1l2f</link>
      <guid>https://dev.to/bhaumik-viitor/unit-test-ai-guide-zero-hallucination-cross-stack-standard-1l2f</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Focus:&lt;/strong&gt; Unit Tests ONLY — no integration, no E2E&lt;br&gt;&lt;br&gt;
&lt;strong&gt;Stacks:&lt;/strong&gt; Node.js (NestJS/Express) · React.js · Python · Angular · Laravel&lt;br&gt;&lt;br&gt;
&lt;strong&gt;Goal:&lt;/strong&gt; AI generates unit tests consistently, deterministically, without hallucination&lt;br&gt;&lt;br&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;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Stack&lt;/th&gt;
&lt;th&gt;Library&lt;/th&gt;
&lt;th&gt;Why This One&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Node.js / NestJS / Express&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;Jest&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Native DI mocking, &lt;code&gt;@nestjs/testing&lt;/code&gt; built around it, widest ecosystem&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;React.js&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;Vitest&lt;/code&gt; + &lt;code&gt;@testing-library/react&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;Native Vite/ESM support, Jest-compatible API, 3–10x faster&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Python&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;pytest&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;De facto standard, fixture system eliminates boilerplate, best plugin ecosystem&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Angular&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;Jest&lt;/code&gt; (replace Karma)&lt;/td&gt;
&lt;td&gt;Karma is deprecated in Angular 17+; Jest is the official migration target&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Laravel&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;Pest&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Modern syntax, built on PHPUnit, higher signal-to-noise ratio&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&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;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Capability&lt;/th&gt;
&lt;th&gt;Cursor&lt;/th&gt;
&lt;th&gt;VS Code + Copilot&lt;/th&gt;
&lt;th&gt;WebStorm&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Project-level AI rules&lt;/td&gt;
&lt;td&gt;✅ &lt;code&gt;.cursor/rules/&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Codebase-aware context&lt;/td&gt;
&lt;td&gt;✅ &lt;code&gt;@codebase&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;Partial&lt;/td&gt;
&lt;td&gt;Partial&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Run terminal + read output&lt;/td&gt;
&lt;td&gt;✅ Composer&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Multi-file generation&lt;/td&gt;
&lt;td&gt;✅ Agent mode&lt;/td&gt;
&lt;td&gt;Limited&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Custom instructions per filetype&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;MCP server integration&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&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="nn"&gt;---&lt;/span&gt;
&lt;span class="na"&gt;description&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Global unit test rules — applies to all files in this project&lt;/span&gt;
&lt;span class="na"&gt;globs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;**/*.spec.ts"&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;**/*.test.ts"&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;**/*.spec.tsx"&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;**/*_test.py"&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;**/Test*.php"&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;
&lt;span class="na"&gt;alwaysApply&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
&lt;span class="nn"&gt;---&lt;/span&gt;

&lt;span class="gh"&gt;# Unit Test Contract — MUST FOLLOW, NO EXCEPTIONS&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="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;br&gt;
// Act — call the single function/method under test&lt;br&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="nn"&gt;---&lt;/span&gt;
&lt;span class="na"&gt;description&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;NestJS unit test rules&lt;/span&gt;
&lt;span class="na"&gt;globs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;src/**/*.service.ts"&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;src/**/*.guard.ts"&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;src/**/*.interceptor.ts"&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;src/**/*.pipe.ts"&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;
&lt;span class="nn"&gt;---&lt;/span&gt;

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

&lt;span class="gu"&gt;## Library: Jest + @nestjs/testing + jest-mock-extended&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;br&gt;
const module = await Test.createTestingModule({&lt;br&gt;
  providers: [&lt;br&gt;
    SubjectService,&lt;br&gt;
    { provide: DependencyService, useValue: mockDependency }&lt;br&gt;
  ]&lt;br&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;br&gt;
import { createMock } from '@golevelup/ts-jest';&lt;br&gt;
// OR&lt;br&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;br&gt;
const mockRepo = {&lt;br&gt;
  findOne: jest.fn(),&lt;br&gt;
  save: jest.fn(),&lt;br&gt;
  delete: jest.fn(),&lt;br&gt;
  findAll: jest.fn(),&lt;br&gt;
  update: jest.fn(),&lt;br&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;br&gt;
import { Test, TestingModule } from '@nestjs/testing';&lt;br&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="nn"&gt;---&lt;/span&gt;
&lt;span class="na"&gt;description&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;React unit test rules&lt;/span&gt;
&lt;span class="na"&gt;globs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;src/**/*.tsx"&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;src/**/*.component.tsx"&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;src/hooks/**/*.ts"&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;
&lt;span class="nn"&gt;---&lt;/span&gt;

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

&lt;span class="gu"&gt;## Library: Vitest + @testing-library/react + @testing-library/user-event&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;br&gt;
export default defineConfig({&lt;br&gt;
  test: {&lt;br&gt;
    environment: 'jsdom',&lt;br&gt;
    globals: true,&lt;br&gt;
    setupFiles: ['./src/test/setup.ts']&lt;br&gt;
  }&lt;br&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;br&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;br&gt;
import { render, screen } from '@testing-library/react';&lt;br&gt;
import userEvent from '@testing-library/user-event';&lt;br&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;br&gt;
const user = userEvent.setup();&lt;br&gt;
await user.click(button);&lt;br&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;br&gt;
import { renderHook, act } from '@testing-library/react';&lt;br&gt;
const { result } = renderHook(() =&amp;gt; useMyHook());&lt;br&gt;
act(() =&amp;gt; result.current.doSomething());&lt;br&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;
markdown&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="nn"&gt;---&lt;/span&gt;
&lt;span class="na"&gt;description&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Python unit test rules&lt;/span&gt;
&lt;span class="na"&gt;globs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;**/*.py"&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;!**/*migrations*"&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;
&lt;span class="nn"&gt;---&lt;/span&gt;

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

&lt;span class="gu"&gt;## Library: pytest + pytest-mock + factory-boy&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="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;br&gt;
    def &lt;strong&gt;init&lt;/strong&gt;(self, repo: UserRepository):&lt;br&gt;
        self.repo = repo&lt;/p&gt;
&lt;h1&gt;
  
  
  BAD — untestable
&lt;/h1&gt;

&lt;p&gt;class UserService:&lt;br&gt;
    def &lt;strong&gt;init&lt;/strong&gt;(self):&lt;br&gt;
        self.repo = UserRepository()  # can't mock this&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 — pytest-mock (mocker fixture)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;&lt;br&gt;
python&lt;br&gt;
def test_raises_when_user_not_found(mocker):&lt;br&gt;
    mock_repo = mocker.Mock()&lt;br&gt;
    mock_repo.find_by_id.return_value = None&lt;br&gt;
    service = UserService(mock_repo)&lt;br&gt;
    with pytest.raises(UserNotFoundException):&lt;br&gt;
        service.get_user("missing-id")&lt;br&gt;
&lt;/p&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;br&gt;
import pytest&lt;/p&gt;

&lt;p&gt;@pytest.mark.asyncio&lt;br&gt;
async def test_async_service(mocker):&lt;br&gt;
    mock_repo = mocker.AsyncMock()&lt;br&gt;
    ...&lt;br&gt;
&lt;/p&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;br&gt;
@pytest.fixture&lt;br&gt;
def user_service(mocker):&lt;br&gt;
    repo = mocker.Mock()&lt;br&gt;
    return UserService(repo), repo&lt;/p&gt;

&lt;p&gt;def test_get_user_happy_path(user_service):&lt;br&gt;
    service, repo = user_service&lt;br&gt;
    repo.find_by_id.return_value = User(id="1", email="&lt;a href="mailto:a@b.com"&gt;a@b.com&lt;/a&gt;")&lt;br&gt;
    result = service.get_user("1")&lt;br&gt;
    assert result.email == "&lt;a href="mailto:a@b.com"&gt;a@b.com&lt;/a&gt;"&lt;br&gt;
&lt;/p&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;
shell&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="nn"&gt;---&lt;/span&gt;
&lt;span class="na"&gt;description&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Angular unit test rules&lt;/span&gt;
&lt;span class="na"&gt;globs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;src/app/**/*.component.ts"&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;src/app/**/*.service.ts"&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;src/app/**/*.pipe.ts"&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;src/app/**/*.guard.ts"&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;
&lt;span class="nn"&gt;---&lt;/span&gt;

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

&lt;span class="gu"&gt;## Library: Jest (NOT Karma — Karma is deprecated Angular 17+)&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;br&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;br&gt;
await TestBed.configureTestingModule({&lt;br&gt;
  imports: [ComponentUnderTest],  // standalone components&lt;br&gt;
  providers: [&lt;br&gt;
    { provide: UserService, useValue: mockUserService }&lt;br&gt;
  ]&lt;br&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;br&gt;
const mockUserService = {&lt;br&gt;
  getUser: jest.fn(),&lt;br&gt;
  createUser: jest.fn(),&lt;br&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;br&gt;
fixture.detectChanges(); // trigger ngOnInit&lt;br&gt;
const button = fixture.debugElement.query(By.css('[data-testid="submit"]'));&lt;br&gt;
button.nativeElement.click();&lt;br&gt;
fixture.detectChanges();&lt;br&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;br&gt;
it('should transform date correctly', () =&amp;gt; {&lt;br&gt;
  const pipe = new DateFormatPipe();&lt;br&gt;
  expect(pipe.transform(new Date('2024-01-01'))).toBe('Jan 1, 2024');&lt;br&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;br&gt;
const guard = TestBed.inject(AuthGuard);&lt;br&gt;
const result = await guard.canActivate(mockRoute, mockState);&lt;br&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;
php&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="nn"&gt;---&lt;/span&gt;
&lt;span class="na"&gt;description&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Laravel unit test rules&lt;/span&gt;
&lt;span class="na"&gt;globs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;app/Services/**/*.php"&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;app/Models/**/*.php"&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;app/Http/Requests/**/*.php"&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;app/Actions/**/*.php"&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;
&lt;span class="nn"&gt;---&lt;/span&gt;

&lt;span class="gh"&gt;# Laravel Unit Test Rules&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="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;br&gt;
class UserService {&lt;br&gt;
    public function __construct(&lt;br&gt;
        private readonly UserRepositoryInterface $repo&lt;br&gt;
    ) {}&lt;br&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;br&gt;
it('throws exception when user not found', function () {&lt;br&gt;
    // Arrange&lt;br&gt;
    $repo = Mockery::mock(UserRepositoryInterface::class);&lt;br&gt;
    $repo-&amp;gt;shouldReceive('findById')-&amp;gt;once()-&amp;gt;andReturn(null);&lt;br&gt;
    $service = new UserService($repo);&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// 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;br&gt;
it('validates email format', function (string $email, bool $valid) {&lt;br&gt;
    expect(validateEmail($email))-&amp;gt;toBe($valid);&lt;br&gt;
})-&amp;gt;with([&lt;br&gt;
    ['&lt;a href="mailto:valid@email.com"&gt;valid@email.com&lt;/a&gt;', true],&lt;br&gt;
    ['notanemail', false],&lt;br&gt;
    ['', false],&lt;br&gt;
    ['@nodomain.com', false],&lt;br&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="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="gu"&gt;## Unit Test Rules — NON-NEGOTIABLE&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="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="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="gu"&gt;### Coverage target: 80% lines, 75% branches per module&lt;/span&gt;

&lt;span class="gu"&gt;## Project Structure Reference&lt;/span&gt;
src/
  modules/
    users/
      users.service.ts
      users.service.spec.ts   ← unit test lives here
      users.repository.ts
      users.repository.spec.ts
&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;Scope: E2E only — not relevant for unit tests&lt;/li&gt;
&lt;li&gt;Skip for this use case&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;Gives Claude access to project files&lt;/li&gt;
&lt;li&gt;Use in Claude Desktop to read source → generate tests&lt;/li&gt;
&lt;li&gt;Install: configured in &lt;code&gt;claude_desktop_config.json&lt;/code&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;Reads a source file&lt;/li&gt;
&lt;li&gt;Extracts function signatures + types&lt;/li&gt;
&lt;li&gt;Returns structured JSON to Claude&lt;/li&gt;
&lt;li&gt;Claude generates tests from structure, not guesswork
&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="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="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 plaintext"&gt;&lt;code&gt;Generate a unit test file for this [NestJS service / React component / Python class / Angular service / Laravel service].

Rules:
- Library: [Jest / Vitest / pytest / Jest / Pest]
- Test only THIS file — no integration
- Mock ALL dependencies listed in the constructor/props
- Follow AAA pattern with comments
- Minimum 4 test cases per public method
- Use ONLY methods/properties that exist in this source file
- Do NOT import anything not shown in the source
- Naming: "should [behavior] when [condition]"
&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 plaintext"&gt;&lt;code&gt;Read [filename].
Extract:
1. Class/function name
2. All public methods with parameter types and return types
3. All constructor dependencies (for mocking)

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 plaintext"&gt;&lt;code&gt;For each file in [directory], generate a corresponding .spec.ts file.
Process one file at a time.
For each file:
  1. Read the source
  2. List the public methods you found (confirm before generating)
  3. Generate the test file
  4. Show the test file path

Do not proceed to the next file until the current one is confirmed.
&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 plaintext"&gt;&lt;code&gt;src/
  modules/
    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;/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="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>unittests</category>
      <category>testing</category>
      <category>cursor</category>
      <category>pytest</category>
    </item>
    <item>
      <title>Unit Test AI Guide — Zero Hallucination, Cross-Stack Standard</title>
      <dc:creator>Bhaumik</dc:creator>
      <pubDate>Tue, 23 Jun 2026 12:09:13 +0000</pubDate>
      <link>https://dev.to/bhaumik-viitor/unit-test-ai-guide-zero-hallucination-cross-stack-standard-3nb8</link>
      <guid>https://dev.to/bhaumik-viitor/unit-test-ai-guide-zero-hallucination-cross-stack-standard-3nb8</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Focus:&lt;/strong&gt; Unit Tests ONLY — no integration, no E2E&lt;br&gt;&lt;br&gt;
&lt;strong&gt;Stacks:&lt;/strong&gt; Node.js (NestJS/Express) · React.js · Python · Angular · Laravel&lt;br&gt;&lt;br&gt;
&lt;strong&gt;Goal:&lt;/strong&gt; AI generates unit tests consistently, deterministically, without hallucination&lt;br&gt;&lt;br&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;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Stack&lt;/th&gt;
&lt;th&gt;Library&lt;/th&gt;
&lt;th&gt;Why This One&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Node.js / NestJS / Express&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;Jest&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Native DI mocking, &lt;code&gt;@nestjs/testing&lt;/code&gt; built around it, widest ecosystem&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;React.js&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;Vitest&lt;/code&gt; + &lt;code&gt;@testing-library/react&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;Native Vite/ESM support, Jest-compatible API, 3–10x faster&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Python&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;pytest&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;De facto standard, fixture system eliminates boilerplate, best plugin ecosystem&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Angular&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;Jest&lt;/code&gt; (replace Karma)&lt;/td&gt;
&lt;td&gt;Karma is deprecated in Angular 17+; Jest is the official migration target&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Laravel&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;Pest&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Modern syntax, built on PHPUnit, higher signal-to-noise ratio&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&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;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Capability&lt;/th&gt;
&lt;th&gt;Cursor&lt;/th&gt;
&lt;th&gt;VS Code + Copilot&lt;/th&gt;
&lt;th&gt;WebStorm&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Project-level AI rules&lt;/td&gt;
&lt;td&gt;✅ &lt;code&gt;.cursor/rules/&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Codebase-aware context&lt;/td&gt;
&lt;td&gt;✅ &lt;code&gt;@codebase&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;Partial&lt;/td&gt;
&lt;td&gt;Partial&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Run terminal + read output&lt;/td&gt;
&lt;td&gt;✅ Composer&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Multi-file generation&lt;/td&gt;
&lt;td&gt;✅ Agent mode&lt;/td&gt;
&lt;td&gt;Limited&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Custom instructions per filetype&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;MCP server integration&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&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="nn"&gt;---&lt;/span&gt;
&lt;span class="na"&gt;description&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Global unit test rules — applies to all files in this project&lt;/span&gt;
&lt;span class="na"&gt;globs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;**/*.spec.ts"&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;**/*.test.ts"&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;**/*.spec.tsx"&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;**/*_test.py"&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;**/Test*.php"&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;
&lt;span class="na"&gt;alwaysApply&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
&lt;span class="nn"&gt;---&lt;/span&gt;

&lt;span class="gh"&gt;# Unit Test Contract — MUST FOLLOW, NO EXCEPTIONS&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="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;br&gt;
// Act — call the single function/method under test&lt;br&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="nn"&gt;---&lt;/span&gt;
&lt;span class="na"&gt;description&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;NestJS unit test rules&lt;/span&gt;
&lt;span class="na"&gt;globs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;src/**/*.service.ts"&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;src/**/*.guard.ts"&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;src/**/*.interceptor.ts"&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;src/**/*.pipe.ts"&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;
&lt;span class="nn"&gt;---&lt;/span&gt;

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

&lt;span class="gu"&gt;## Library: Jest + @nestjs/testing + jest-mock-extended&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;br&gt;
const module = await Test.createTestingModule({&lt;br&gt;
  providers: [&lt;br&gt;
    SubjectService,&lt;br&gt;
    { provide: DependencyService, useValue: mockDependency }&lt;br&gt;
  ]&lt;br&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;br&gt;
import { createMock } from '@golevelup/ts-jest';&lt;br&gt;
// OR&lt;br&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;br&gt;
const mockRepo = {&lt;br&gt;
  findOne: jest.fn(),&lt;br&gt;
  save: jest.fn(),&lt;br&gt;
  delete: jest.fn(),&lt;br&gt;
  findAll: jest.fn(),&lt;br&gt;
  update: jest.fn(),&lt;br&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;br&gt;
import { Test, TestingModule } from '@nestjs/testing';&lt;br&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="nn"&gt;---&lt;/span&gt;
&lt;span class="na"&gt;description&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;React unit test rules&lt;/span&gt;
&lt;span class="na"&gt;globs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;src/**/*.tsx"&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;src/**/*.component.tsx"&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;src/hooks/**/*.ts"&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;
&lt;span class="nn"&gt;---&lt;/span&gt;

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

&lt;span class="gu"&gt;## Library: Vitest + @testing-library/react + @testing-library/user-event&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;br&gt;
export default defineConfig({&lt;br&gt;
  test: {&lt;br&gt;
    environment: 'jsdom',&lt;br&gt;
    globals: true,&lt;br&gt;
    setupFiles: ['./src/test/setup.ts']&lt;br&gt;
  }&lt;br&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;br&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;br&gt;
import { render, screen } from '@testing-library/react';&lt;br&gt;
import userEvent from '@testing-library/user-event';&lt;br&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;br&gt;
const user = userEvent.setup();&lt;br&gt;
await user.click(button);&lt;br&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;br&gt;
import { renderHook, act } from '@testing-library/react';&lt;br&gt;
const { result } = renderHook(() =&amp;gt; useMyHook());&lt;br&gt;
act(() =&amp;gt; result.current.doSomething());&lt;br&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;
markdown&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="nn"&gt;---&lt;/span&gt;
&lt;span class="na"&gt;description&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Python unit test rules&lt;/span&gt;
&lt;span class="na"&gt;globs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;**/*.py"&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;!**/*migrations*"&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;
&lt;span class="nn"&gt;---&lt;/span&gt;

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

&lt;span class="gu"&gt;## Library: pytest + pytest-mock + factory-boy&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="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;br&gt;
    def &lt;strong&gt;init&lt;/strong&gt;(self, repo: UserRepository):&lt;br&gt;
        self.repo = repo&lt;/p&gt;
&lt;h1&gt;
  
  
  BAD — untestable
&lt;/h1&gt;

&lt;p&gt;class UserService:&lt;br&gt;
    def &lt;strong&gt;init&lt;/strong&gt;(self):&lt;br&gt;
        self.repo = UserRepository()  # can't mock this&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 — pytest-mock (mocker fixture)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;&lt;br&gt;
python&lt;br&gt;
def test_raises_when_user_not_found(mocker):&lt;br&gt;
    mock_repo = mocker.Mock()&lt;br&gt;
    mock_repo.find_by_id.return_value = None&lt;br&gt;
    service = UserService(mock_repo)&lt;br&gt;
    with pytest.raises(UserNotFoundException):&lt;br&gt;
        service.get_user("missing-id")&lt;br&gt;
&lt;/p&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;br&gt;
import pytest&lt;/p&gt;

&lt;p&gt;@pytest.mark.asyncio&lt;br&gt;
async def test_async_service(mocker):&lt;br&gt;
    mock_repo = mocker.AsyncMock()&lt;br&gt;
    ...&lt;br&gt;
&lt;/p&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;br&gt;
@pytest.fixture&lt;br&gt;
def user_service(mocker):&lt;br&gt;
    repo = mocker.Mock()&lt;br&gt;
    return UserService(repo), repo&lt;/p&gt;

&lt;p&gt;def test_get_user_happy_path(user_service):&lt;br&gt;
    service, repo = user_service&lt;br&gt;
    repo.find_by_id.return_value = User(id="1", email="&lt;a href="mailto:a@b.com"&gt;a@b.com&lt;/a&gt;")&lt;br&gt;
    result = service.get_user("1")&lt;br&gt;
    assert result.email == "&lt;a href="mailto:a@b.com"&gt;a@b.com&lt;/a&gt;"&lt;br&gt;
&lt;/p&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;
shell&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="nn"&gt;---&lt;/span&gt;
&lt;span class="na"&gt;description&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Angular unit test rules&lt;/span&gt;
&lt;span class="na"&gt;globs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;src/app/**/*.component.ts"&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;src/app/**/*.service.ts"&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;src/app/**/*.pipe.ts"&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;src/app/**/*.guard.ts"&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;
&lt;span class="nn"&gt;---&lt;/span&gt;

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

&lt;span class="gu"&gt;## Library: Jest (NOT Karma — Karma is deprecated Angular 17+)&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;br&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;br&gt;
await TestBed.configureTestingModule({&lt;br&gt;
  imports: [ComponentUnderTest],  // standalone components&lt;br&gt;
  providers: [&lt;br&gt;
    { provide: UserService, useValue: mockUserService }&lt;br&gt;
  ]&lt;br&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;br&gt;
const mockUserService = {&lt;br&gt;
  getUser: jest.fn(),&lt;br&gt;
  createUser: jest.fn(),&lt;br&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;br&gt;
fixture.detectChanges(); // trigger ngOnInit&lt;br&gt;
const button = fixture.debugElement.query(By.css('[data-testid="submit"]'));&lt;br&gt;
button.nativeElement.click();&lt;br&gt;
fixture.detectChanges();&lt;br&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;br&gt;
it('should transform date correctly', () =&amp;gt; {&lt;br&gt;
  const pipe = new DateFormatPipe();&lt;br&gt;
  expect(pipe.transform(new Date('2024-01-01'))).toBe('Jan 1, 2024');&lt;br&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;br&gt;
const guard = TestBed.inject(AuthGuard);&lt;br&gt;
const result = await guard.canActivate(mockRoute, mockState);&lt;br&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;
php&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="nn"&gt;---&lt;/span&gt;
&lt;span class="na"&gt;description&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Laravel unit test rules&lt;/span&gt;
&lt;span class="na"&gt;globs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;app/Services/**/*.php"&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;app/Models/**/*.php"&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;app/Http/Requests/**/*.php"&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;app/Actions/**/*.php"&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;
&lt;span class="nn"&gt;---&lt;/span&gt;

&lt;span class="gh"&gt;# Laravel Unit Test Rules&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="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;br&gt;
class UserService {&lt;br&gt;
    public function __construct(&lt;br&gt;
        private readonly UserRepositoryInterface $repo&lt;br&gt;
    ) {}&lt;br&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;br&gt;
it('throws exception when user not found', function () {&lt;br&gt;
    // Arrange&lt;br&gt;
    $repo = Mockery::mock(UserRepositoryInterface::class);&lt;br&gt;
    $repo-&amp;gt;shouldReceive('findById')-&amp;gt;once()-&amp;gt;andReturn(null);&lt;br&gt;
    $service = new UserService($repo);&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// 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;br&gt;
it('validates email format', function (string $email, bool $valid) {&lt;br&gt;
    expect(validateEmail($email))-&amp;gt;toBe($valid);&lt;br&gt;
})-&amp;gt;with([&lt;br&gt;
    ['&lt;a href="mailto:valid@email.com"&gt;valid@email.com&lt;/a&gt;', true],&lt;br&gt;
    ['notanemail', false],&lt;br&gt;
    ['', false],&lt;br&gt;
    ['@nodomain.com', false],&lt;br&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="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="gu"&gt;## Unit Test Rules — NON-NEGOTIABLE&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="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="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="gu"&gt;### Coverage target: 80% lines, 75% branches per module&lt;/span&gt;

&lt;span class="gu"&gt;## Project Structure Reference&lt;/span&gt;
src/
  modules/
    users/
      users.service.ts
      users.service.spec.ts   ← unit test lives here
      users.repository.ts
      users.repository.spec.ts
&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;Scope: E2E only — not relevant for unit tests&lt;/li&gt;
&lt;li&gt;Skip for this use case&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;Gives Claude access to project files&lt;/li&gt;
&lt;li&gt;Use in Claude Desktop to read source → generate tests&lt;/li&gt;
&lt;li&gt;Install: configured in &lt;code&gt;claude_desktop_config.json&lt;/code&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;Reads a source file&lt;/li&gt;
&lt;li&gt;Extracts function signatures + types&lt;/li&gt;
&lt;li&gt;Returns structured JSON to Claude&lt;/li&gt;
&lt;li&gt;Claude generates tests from structure, not guesswork
&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="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="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 plaintext"&gt;&lt;code&gt;Generate a unit test file for this [NestJS service / React component / Python class / Angular service / Laravel service].

Rules:
- Library: [Jest / Vitest / pytest / Jest / Pest]
- Test only THIS file — no integration
- Mock ALL dependencies listed in the constructor/props
- Follow AAA pattern with comments
- Minimum 4 test cases per public method
- Use ONLY methods/properties that exist in this source file
- Do NOT import anything not shown in the source
- Naming: "should [behavior] when [condition]"
&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 plaintext"&gt;&lt;code&gt;Read [filename].
Extract:
1. Class/function name
2. All public methods with parameter types and return types
3. All constructor dependencies (for mocking)

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 plaintext"&gt;&lt;code&gt;For each file in [directory], generate a corresponding .spec.ts file.
Process one file at a time.
For each file:
  1. Read the source
  2. List the public methods you found (confirm before generating)
  3. Generate the test file
  4. Show the test file path

Do not proceed to the next file until the current one is confirmed.
&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 plaintext"&gt;&lt;code&gt;src/
  modules/
    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;/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="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>unittests</category>
      <category>testing</category>
      <category>cursor</category>
      <category>pytest</category>
    </item>
    <item>
      <title>(untitled)</title>
      <dc:creator>Bhaumik</dc:creator>
      <pubDate>Tue, 23 Jun 2026 11:33:09 +0000</pubDate>
      <link>https://dev.to/bhaumik-viitor/untitled-44he</link>
      <guid>https://dev.to/bhaumik-viitor/untitled-44he</guid>
      <description>&lt;h1&gt;
  
  
  TDD Industry Standard Guide — Full Stack R&amp;amp;D Reference
&lt;/h1&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Scope:&lt;/strong&gt; Node.js · NestJS · Express.js · React · Next.js · Angular · Python · Laravel&lt;br&gt;&lt;br&gt;
&lt;strong&gt;Audience:&lt;/strong&gt; Engineering teams adopting or scaling TDD practices&lt;br&gt;&lt;br&gt;
&lt;strong&gt;Version:&lt;/strong&gt; 2025 — reflects current ecosystem state&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  Part 1 — What Is TDD and How It Works
&lt;/h2&gt;

&lt;h3&gt;
  
  
  1.1 Core Philosophy
&lt;/h3&gt;

&lt;p&gt;TDD (Test-Driven Development) is a development methodology where &lt;strong&gt;tests are written before the production code&lt;/strong&gt;. It inverts the traditional flow — instead of writing code then checking if it works, you first define what "working" means.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Red → Green → Refactor&lt;/strong&gt; cycle:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;1. RED    — Write a failing test for a behavior that doesn't exist yet
2. GREEN  — Write the minimum code required to make that test pass
3. REFACTOR — Clean up the code without breaking the test
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This isn't just about testing — it's a &lt;strong&gt;design discipline&lt;/strong&gt;. Forcing yourself to write tests first exposes bad API design, tight coupling, and unclear responsibilities before they're baked into code.&lt;/p&gt;

&lt;h3&gt;
  
  
  1.2 TDD vs BDD vs ATDD
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Approach&lt;/th&gt;
&lt;th&gt;Who writes&lt;/th&gt;
&lt;th&gt;Language&lt;/th&gt;
&lt;th&gt;Focus&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;TDD&lt;/td&gt;
&lt;td&gt;Developer&lt;/td&gt;
&lt;td&gt;Code/assertions&lt;/td&gt;
&lt;td&gt;Unit behavior&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;BDD&lt;/td&gt;
&lt;td&gt;Dev + QA&lt;/td&gt;
&lt;td&gt;Gherkin (Given/When/Then)&lt;/td&gt;
&lt;td&gt;User scenarios&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;ATDD&lt;/td&gt;
&lt;td&gt;Dev + QA + Business&lt;/td&gt;
&lt;td&gt;Acceptance criteria&lt;/td&gt;
&lt;td&gt;System behavior&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;In practice, most production teams use &lt;strong&gt;TDD for units + BDD for integration/E2E&lt;/strong&gt;. Pure ATDD is rare outside regulated industries.&lt;/p&gt;

&lt;h3&gt;
  
  
  1.3 The Test Pyramid (Industry Standard Model)
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;          /\
         /  \
        / E2E \          ~10% — Slow, expensive, brittle
       /--------\
      /Integration\      ~20% — Services, DB, APIs
     /--------------\
    /   Unit Tests   \   ~70% — Fast, isolated, numerous
   /------------------\
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Invert this ratio = test anti-pattern&lt;/strong&gt; (too many E2E tests = slow CI, fragile suite).&lt;/p&gt;




&lt;h2&gt;
  
  
  Part 2 — Test Types and What to Cover
&lt;/h2&gt;

&lt;h3&gt;
  
  
  2.1 Unit Tests
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Test a &lt;strong&gt;single function, class, or module in isolation&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;All dependencies are mocked/stubbed&lt;/li&gt;
&lt;li&gt;Should run in &lt;strong&gt;&amp;lt; 50ms per test&lt;/strong&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Cover:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Pure functions (transformation, calculation, formatting)&lt;/li&gt;
&lt;li&gt;Service layer business logic&lt;/li&gt;
&lt;li&gt;Guards, interceptors, middlewares&lt;/li&gt;
&lt;li&gt;Validators and DTOs&lt;/li&gt;
&lt;li&gt;Utility helpers&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  2.2 Integration Tests
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Test &lt;strong&gt;two or more real components together&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;May hit a real DB (test DB), real service layer, real HTTP handler&lt;/li&gt;
&lt;li&gt;Slower than unit tests but critical for wiring validation&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Cover:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Controller → Service → Repository chain&lt;/li&gt;
&lt;li&gt;Database queries with real schema&lt;/li&gt;
&lt;li&gt;Auth flows (token issuance + validation)&lt;/li&gt;
&lt;li&gt;Event-driven pipelines (queue → handler)&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  2.3 E2E Tests
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Test the &lt;strong&gt;full system from HTTP request to response&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Often uses a real or in-memory database&lt;/li&gt;
&lt;li&gt;Validates complete user workflows&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Cover:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Critical user journeys (login, checkout, form submission)&lt;/li&gt;
&lt;li&gt;API contract validation&lt;/li&gt;
&lt;li&gt;Cross-service flows in microservices&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  2.4 Contract Tests (Underused but Valuable)
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Tests &lt;strong&gt;API contracts between producer and consumer&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Tool: &lt;strong&gt;Pact.js&lt;/strong&gt; (Node), &lt;strong&gt;Pactflow&lt;/strong&gt; (SaaS)&lt;/li&gt;
&lt;li&gt;Essential in microservices architectures&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  2.5 Snapshot Tests
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Capture rendered output and &lt;strong&gt;detect unintended changes&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Best for UI components (React, Angular)&lt;/li&gt;
&lt;li&gt;Overuse leads to meaningless "approve all snapshots" habit&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  2.6 Test Case Identification Strategy
&lt;/h3&gt;

&lt;p&gt;Before writing tests, apply these techniques:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Equivalence Partitioning&lt;/strong&gt; — Group inputs into classes that behave the same&lt;br&gt;&lt;br&gt;
&lt;strong&gt;Boundary Value Analysis&lt;/strong&gt; — Test at edges (0, -1, max, max+1)&lt;br&gt;&lt;br&gt;
&lt;strong&gt;Decision Table Testing&lt;/strong&gt; — Matrix of conditions vs outcomes&lt;br&gt;&lt;br&gt;
&lt;strong&gt;State Transition&lt;/strong&gt; — For stateful flows (e.g., order status machine)&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;For each function/module ask:
  ✓ Happy path — expected input → expected output
  ✓ Edge cases — empty, null, zero, max values
  ✓ Error paths — invalid input, network fail, DB error
  ✓ Security paths — injection, unauthorized access, rate limits
  ✓ Concurrency — race conditions, duplicate requests
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Part 3 — Stack-Specific Setup
&lt;/h2&gt;

&lt;h3&gt;
  
  
  3.1 Node.js (Generic)
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Packages:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"devDependencies"&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;"jest"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"^29.x"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"ts-jest"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"^29.x"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"@types/jest"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"^29.x"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"supertest"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"^6.x"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"nock"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"^13.x"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"faker"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"^8.x"&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;p&gt;&lt;strong&gt;jest.config.ts:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;preset&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;ts-jest&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;testEnvironment&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;node&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;roots&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;&amp;lt;rootDir&amp;gt;/src&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
  &lt;span class="na"&gt;testMatch&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;**/*.spec.ts&lt;/span&gt;&lt;span class="dl"&gt;'&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.ts&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
  &lt;span class="na"&gt;coverageThreshold&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;global&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;branches&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;80&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;functions&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;80&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;lines&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;80&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;statements&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;80&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="na"&gt;collectCoverageFrom&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;src/**/*.ts&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;!src/**/*.module.ts&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;!src/main.ts&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h3&gt;
  
  
  3.2 NestJS (Primary Recommendation for Node APIs)
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Packages (built-in + additions):&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"devDependencies"&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;"@nestjs/testing"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"^10.x"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"jest"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"^29.x"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"ts-jest"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"^29.x"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"supertest"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"^6.x"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"@testcontainers/postgresql"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"^10.x"&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;p&gt;&lt;strong&gt;Unit Test — Service (Red → Green example):&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// users.service.spec.ts — RED phase&lt;/span&gt;
&lt;span class="nf"&gt;describe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;UsersService&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="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="na"&gt;service&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;UsersService&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="na"&gt;repo&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;jest&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Mocked&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;UserRepository&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="nf"&gt;beforeEach&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="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="kr"&gt;module&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;Test&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;createTestingModule&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
      &lt;span class="na"&gt;providers&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
        &lt;span class="nx"&gt;UsersService&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;
          &lt;span class="na"&gt;provide&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;UserRepository&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
          &lt;span class="na"&gt;useValue&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="na"&gt;findOne&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;jest&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;fn&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
            &lt;span class="na"&gt;save&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;jest&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;fn&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="nf"&gt;compile&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

    &lt;span class="nx"&gt;service&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kr"&gt;module&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;UsersService&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nx"&gt;repo&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kr"&gt;module&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;UserRepository&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;

  &lt;span class="nf"&gt;it&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;should throw NotFoundException when user does not exist&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="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;repo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;findOne&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;mockResolvedValue&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;service&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;findById&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;non-existent-id&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)).&lt;/span&gt;&lt;span class="nx"&gt;rejects&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;toThrow&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;NotFoundException&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Integration Test — Controller with real HTTP:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// users.e2e-spec.ts&lt;/span&gt;
&lt;span class="nf"&gt;describe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;POST /users&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="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="na"&gt;app&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;INestApplication&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="nf"&gt;beforeAll&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="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="kr"&gt;module&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;Test&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;createTestingModule&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
      &lt;span class="na"&gt;imports&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;AppModule&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="p"&gt;}).&lt;/span&gt;&lt;span class="nf"&gt;compile&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="nx"&gt;app&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kr"&gt;module&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;createNestApplication&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;init&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;

  &lt;span class="nf"&gt;it&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;should create user and return 201&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="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;request&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getHttpServer&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
      &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;post&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/users&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="nf"&gt;send&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;email&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@example.com&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;password&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;securePass123&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="nf"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;201&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;res&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nf"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;body&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;toHaveProperty&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;id&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="nf"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;body&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;email&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;toBe&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@example.com&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="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;Testcontainers (Real DB in CI):&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;container&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;PostgreSqlContainer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;postgres:15&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;start&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="c1"&gt;// inject connection string into TypeORM config&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h3&gt;
  
  
  3.3 Express.js
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Minimal setup, no DI framework — use jest + supertest&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;request&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;supertest&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="nx"&gt;app&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;../app&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// your express app&lt;/span&gt;

&lt;span class="nf"&gt;describe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;GET /health&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="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nf"&gt;it&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;returns 200 with status ok&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="o"&gt;=&amp;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;res&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;request&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/health&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nf"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;status&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;toBe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;200&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nf"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;body&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;status&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;toBe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;ok&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="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Key difference from NestJS:&lt;/strong&gt; No built-in DI, so use dependency injection manually or use a light container like &lt;code&gt;awilix&lt;/code&gt; for testability.&lt;/p&gt;




&lt;h3&gt;
  
  
  3.4 React.js
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Packages:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"devDependencies"&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;"@testing-library/react"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"^14.x"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"@testing-library/user-event"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"^14.x"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"@testing-library/jest-dom"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"^6.x"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"msw"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"^2.x"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"vitest"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"^1.x"&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;p&gt;&lt;strong&gt;Vitest is now preferred over Jest for React/Vite projects&lt;/strong&gt; (2024+)&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// LoginForm.test.tsx&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;render&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;screen&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;@testing-library/react&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="nx"&gt;userEvent&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;@testing-library/user-event&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="nf"&gt;describe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;LoginForm&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="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nf"&gt;it&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;should show error when email is invalid&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="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;render&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;LoginForm&lt;/span&gt; &lt;span class="nx"&gt;onSubmit&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;jest&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;fn&lt;/span&gt;&lt;span class="p"&gt;()}&lt;/span&gt; &lt;span class="sr"&gt;/&amp;gt;&lt;/span&gt;&lt;span class="se"&gt;)&lt;/span&gt;&lt;span class="err"&gt;;
&lt;/span&gt;    &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;userEvent&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;type&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;screen&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getByLabelText&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Email&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;notvalid&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;userEvent&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;click&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;screen&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getByRole&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;button&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;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sr"&gt;/submit/i&lt;/span&gt; &lt;span class="p"&gt;}));&lt;/span&gt;
    &lt;span class="nf"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;screen&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getByText&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sr"&gt;/invalid email/i&lt;/span&gt;&lt;span class="p"&gt;)).&lt;/span&gt;&lt;span class="nf"&gt;toBeInTheDocument&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;MSW for API Mocking (industry standard):&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;http&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;HttpResponse&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;msw&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;setupServer&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;msw/node&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="nf"&gt;setupServer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="nx"&gt;http&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/api/users&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="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;HttpResponse&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;([{&lt;/span&gt; &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;1&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;Bhaumik&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h3&gt;
  
  
  3.5 Next.js
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Additional considerations:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Test &lt;strong&gt;Server Components&lt;/strong&gt; differently from Client Components&lt;/li&gt;
&lt;li&gt;Use &lt;code&gt;@testing-library/react&lt;/code&gt; for client components&lt;/li&gt;
&lt;li&gt;Use &lt;strong&gt;Playwright&lt;/strong&gt; or &lt;strong&gt;Cypress&lt;/strong&gt; for full E2E (including SSR flows)
&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;// app/actions/create-user.test.ts (Server Action testing)&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;createUser&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;./create-user&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="nf"&gt;it&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;should return validation error for short password&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="o"&gt;=&amp;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;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;createUser&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;email&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;a@b.com&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;password&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;123&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
  &lt;span class="nf"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;toBe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Password too short&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






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

&lt;p&gt;&lt;strong&gt;Built-in: Jasmine + Karma (legacy) → now migrating to Jest + Vitest&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// users.component.spec.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;ComponentFixture&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;TestBed&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;@angular/core/testing&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;provideHttpClientTesting&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;@angular/common/http/testing&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="nf"&gt;describe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;UsersComponent&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="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="na"&gt;component&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;UsersComponent&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="na"&gt;fixture&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;ComponentFixture&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;UsersComponent&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="nf"&gt;beforeEach&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="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;TestBed&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;configureTestingModule&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
      &lt;span class="na"&gt;imports&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;UsersComponent&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
      &lt;span class="na"&gt;providers&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nf"&gt;provideHttpClientTesting&lt;/span&gt;&lt;span class="p"&gt;()]&lt;/span&gt;
    &lt;span class="p"&gt;}).&lt;/span&gt;&lt;span class="nf"&gt;compileComponents&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="nx"&gt;fixture&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;TestBed&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;createComponent&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;UsersComponent&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nx"&gt;component&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;fixture&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;componentInstance&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;

  &lt;span class="nf"&gt;it&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;should display users from service&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="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;component&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;toBeTruthy&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Angular 17+ recommendation: Use &lt;code&gt;@analogjs/vitest-angular&lt;/code&gt; for faster testing.&lt;/strong&gt;&lt;/p&gt;




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

&lt;p&gt;&lt;strong&gt;Packages:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;pytest
pytest-cov
pytest-asyncio
pytest-mock
factory-boy
httpx (for async API tests)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;# test_user_service.py
&lt;/span&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;pytest&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;unittest.mock&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;AsyncMock&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;app.services.user_service&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;UserService&lt;/span&gt;

&lt;span class="nd"&gt;@pytest.mark.asyncio&lt;/span&gt;
&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;test_raises_not_found_when_user_missing&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
    &lt;span class="n"&gt;repo&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;AsyncMock&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="n"&gt;repo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;find_by_id&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;return_value&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;
    &lt;span class="n"&gt;service&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;UserService&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;repo&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;with&lt;/span&gt; &lt;span class="n"&gt;pytest&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;raises&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;UserNotFoundException&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;service&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get_user&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;missing-id&lt;/span&gt;&lt;span class="sh"&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;FastAPI integration test:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;httpx&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;AsyncClient&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;app.main&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;app&lt;/span&gt;

&lt;span class="nd"&gt;@pytest.mark.asyncio&lt;/span&gt;
&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;test_create_user_returns_201&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
    &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="k"&gt;with&lt;/span&gt; &lt;span class="nc"&gt;AsyncClient&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;base_url&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;http://test&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;post&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;/users&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;json&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;email&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;a@b.com&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;})&lt;/span&gt;
    &lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;status_code&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;201&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






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

&lt;p&gt;&lt;strong&gt;Built-in: PHPUnit + Pest (recommended for modern projects)&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="c1"&gt;// tests/Unit/UserServiceTest.php (Pest)&lt;/span&gt;
&lt;span class="nf"&gt;it&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'throws exception when user not found'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nv"&gt;$repo&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Mockery&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;mock&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;UserRepository&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;class&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nv"&gt;$repo&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;shouldReceive&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'findById'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;andReturn&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="nv"&gt;$service&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;UserService&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$repo&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nf"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nv"&gt;$service&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;getUser&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'abc'&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;toThrow&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;UserNotFoundException&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;class&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;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Feature test (Integration)&lt;/span&gt;
&lt;span class="nf"&gt;it&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'creates user via API'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nv"&gt;$response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;postJson&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'/api/users'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
        &lt;span class="s1"&gt;'email'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s1"&gt;'test@example.com'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="s1"&gt;'password'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s1"&gt;'securePass123'&lt;/span&gt;
    &lt;span class="p"&gt;]);&lt;/span&gt;
    &lt;span class="nv"&gt;$response&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;assertStatus&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;201&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;assertJsonStructure&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="s1"&gt;'id'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'email'&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;
    &lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;assertDatabaseHas&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'users'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'email'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s1"&gt;'test@example.com'&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;h2&gt;
  
  
  Part 4 — TDD Flow in Practice
&lt;/h2&gt;

&lt;h3&gt;
  
  
  4.1 Standard TDD Workflow
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Feature Requirement
        │
        ▼
  Identify Test Cases
  (unit → integration → e2e)
        │
        ▼
   Write Failing Test ──────────────────────┐
        │                                   │
        ▼                                   │
   Run Test → FAIL (RED) ✓                  │
        │                                   │
        ▼                                   │
   Write Minimum Code to Pass               │
        │                                   │
        ▼                                   │
   Run Test → PASS (GREEN) ✓                │
        │                                   │
        ▼                                   │
   Refactor (extract, simplify, type)       │
        │                                   │
        ▼                                   │
   Run All Tests → PASS ✓                   │
        │                                   │
        ▼                                   │
   Next Test Case ──────────────────────────┘
        │
        ▼
   PR + CI enforces coverage gate
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  4.2 TDD for New Projects
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;1. Set up test infrastructure FIRST (jest, coverage config, CI pipeline)
2. Define interfaces/contracts before implementations
3. Write service interface → test against interface → implement
4. Bottom-up: Repository → Service → Controller → E2E
5. Enforce coverage thresholds from day 1 (80% min)
6. Commit convention: test commits separate from feature commits
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  4.3 TDD for Legacy Projects (Retroactive)
&lt;/h3&gt;

&lt;p&gt;This is harder. Use the &lt;strong&gt;Strangler Fig Pattern:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;1. Do NOT rewrite everything — add tests around existing code first
2. Identify critical paths → write characterization tests first
   (these capture CURRENT behavior, not ideal behavior)
3. Refactor module by module, protected by characterization tests
4. Replace legacy code with TDD-developed replacements incrementally
5. Track coverage per module — set increasing baselines per sprint
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Tool: Istanbul/c8 (JS), Coverage.py (Python), Xdebug (PHP)&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Use &lt;code&gt;--coverage-threshold&lt;/code&gt; flags per directory for gradual enforcement.&lt;/p&gt;




&lt;h2&gt;
  
  
  Part 5 — AI-Assisted TDD: The Wrapper System
&lt;/h2&gt;

&lt;p&gt;This is your key architectural challenge: &lt;strong&gt;how do you ensure AI-generated code also meets your TDD standards?&lt;/strong&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  5.1 The Problem
&lt;/h3&gt;

&lt;p&gt;AI tools (Cursor, GitHub Copilot, Claude) generate code without context of your test standards. Developers may accept generated code without tests, leading to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Inconsistent test naming conventions&lt;/li&gt;
&lt;li&gt;Missing edge case coverage&lt;/li&gt;
&lt;li&gt;Wrong test granularity&lt;/li&gt;
&lt;li&gt;Tests that don't follow AAA (Arrange-Act-Assert) pattern&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  5.2 The Solution: TDD Standards Wrapper System
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Layer 1 — Project-Level Rules File&lt;/strong&gt; (&lt;code&gt;.cursorrules&lt;/code&gt; or &lt;code&gt;CLAUDE.md&lt;/code&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;# TDD Contract — All Code Generated Must Follow These Rules&lt;/span&gt;

&lt;span class="gu"&gt;## Test Requirements&lt;/span&gt;
&lt;span class="p"&gt;-&lt;/span&gt; Every function/method must have a corresponding .spec.ts file
&lt;span class="p"&gt;-&lt;/span&gt; Tests follow AAA: Arrange → Act → Assert — labeled with comments
&lt;span class="p"&gt;-&lt;/span&gt; Unit tests must mock ALL external dependencies
&lt;span class="p"&gt;-&lt;/span&gt; No test should depend on another test's state
&lt;span class="p"&gt;-&lt;/span&gt; Minimum one test per: happy path, error path, edge case

&lt;span class="gu"&gt;## Naming Convention&lt;/span&gt;
&lt;span class="p"&gt;-&lt;/span&gt; Test file: [module].spec.ts (unit) / [module].e2e-spec.ts (integration)
&lt;span class="p"&gt;-&lt;/span&gt; Describe block: class/function name
&lt;span class="p"&gt;-&lt;/span&gt; It block: "should [expected behavior] when [condition]"

&lt;span class="gu"&gt;## Coverage Gate&lt;/span&gt;
&lt;span class="p"&gt;-&lt;/span&gt; Lines: 80%, Branches: 75%, Functions: 80%
&lt;span class="p"&gt;-&lt;/span&gt; New modules must not lower global coverage

&lt;span class="gu"&gt;## Test Structure Template&lt;/span&gt;
describe('[ModuleName]', () =&amp;gt; {
  // Setup
  beforeEach(() =&amp;gt; { /&lt;span class="ge"&gt;* setup *&lt;/span&gt;/ });
  afterEach(() =&amp;gt; { /&lt;span class="ge"&gt;* cleanup *&lt;/span&gt;/ });

  describe('[methodName]', () =&amp;gt; {
    it('should [behavior] when [condition]', () =&amp;gt; {
      // Arrange
      // Act
      // Assert
    });
  });
});
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Layer 2 — AI Prompt Wrapper (System Prompt / Custom Instructions)&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;When using Claude/Cursor for code generation, prefix with:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;You are a senior engineer following strict TDD standards.
For every code change you make:
1. First output the test file (.spec.ts) using Jest + AAA pattern
2. Then output the implementation file
3. All external deps must be mocked in unit tests
4. Follow naming: "should [behavior] when [condition]"
5. Include: happy path, null/undefined edge case, error case
6. Do NOT write implementation before the test
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Store this as:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;/prompts/tdd-code-gen.md&lt;/code&gt; — for manual use&lt;/li&gt;
&lt;li&gt;Cursor &lt;code&gt;.cursorrules&lt;/code&gt; — auto-injected to all AI interactions&lt;/li&gt;
&lt;li&gt;VS Code snippet — for quick scaffold generation&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Layer 3 — Pre-commit Hooks (Enforcement)&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&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/**/*.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 --coverage"&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;"husky"&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;"pre-commit"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&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="nl"&gt;"pre-push"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"jest --coverage --coverageThreshold='{&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;global&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;:{&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;lines&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;:80}}'"&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;p&gt;&lt;strong&gt;Layer 4 — CI Pipeline Gate&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="c1"&gt;# .github/workflows/test.yml&lt;/span&gt;
&lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Run Tests with Coverage&lt;/span&gt;
  &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;|&lt;/span&gt;
    &lt;span class="s"&gt;npm run test:cov&lt;/span&gt;
    &lt;span class="s"&gt;# Fail if coverage drops below threshold&lt;/span&gt;
    &lt;span class="s"&gt;npx jest --coverage --coverageThreshold='{"global":{"lines":80,"branches":75}}'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Layer 5 — ESLint Test Rules&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="err"&gt;//&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;eslint&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;plugin:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;eslint-plugin-jest&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;"plugins"&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"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"rules"&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;"jest/expect-expect"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"error"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"jest/no-disabled-tests"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"warn"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"jest/no-focused-tests"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"error"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"jest/valid-expect"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"error"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"jest/consistent-test-it"&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;"error"&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;"fn"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"it"&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 — Test Generation: Manual vs Automated
&lt;/h2&gt;

&lt;h3&gt;
  
  
  6.1 Manual Generation (AI-Assisted, Human-Reviewed)
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Workflow:&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Developer writes interface/type → prompts AI for test scaffold&lt;/li&gt;
&lt;li&gt;AI generates test file using prompt wrapper (Layer 2)&lt;/li&gt;
&lt;li&gt;Developer reviews, adds domain-specific edge cases&lt;/li&gt;
&lt;li&gt;AI fills implementation given tests&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;strong&gt;Cursor workflow:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;1. Create users.service.ts with method signatures only
2. Cmd+K: "Generate TDD tests for this service following .cursorrules"
3. Review + commit test file
4. Cmd+K: "Implement service methods to make these tests pass"
5. Run tests → iterate
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  6.2 Automated Generation Tools
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Tool&lt;/th&gt;
&lt;th&gt;Language&lt;/th&gt;
&lt;th&gt;Type&lt;/th&gt;
&lt;th&gt;Notes&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Copilot Test Agent&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;All&lt;/td&gt;
&lt;td&gt;AI-gen&lt;/td&gt;
&lt;td&gt;GitHub Copilot feature&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;CodiumAI / Qodo&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;JS/TS/Python&lt;/td&gt;
&lt;td&gt;AI-gen unit&lt;/td&gt;
&lt;td&gt;Best for auto unit test gen&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;diffblue Cover&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Java&lt;/td&gt;
&lt;td&gt;AI&lt;/td&gt;
&lt;td&gt;Enterprise Java only&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Pynguin&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Python&lt;/td&gt;
&lt;td&gt;Search-based&lt;/td&gt;
&lt;td&gt;Academic, generates pytest&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;TestPilot&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;JS&lt;/td&gt;
&lt;td&gt;AI&lt;/td&gt;
&lt;td&gt;Microsoft Research tool&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;jest-auto-spies&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;TS&lt;/td&gt;
&lt;td&gt;Helper&lt;/td&gt;
&lt;td&gt;Auto-generates spy objects&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;CodiumAI/Qodo&lt;/strong&gt; is the current industry leader for automatic test generation in JS/TS/Python. It analyzes function signatures and generates multiple test cases automatically.&lt;/p&gt;

&lt;h3&gt;
  
  
  6.3 Scaffold Generation CLI (Custom Team Tool)
&lt;/h3&gt;

&lt;p&gt;Build your own test scaffold generator:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// scripts/generate-test.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;execSync&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;child_process&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;fs&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;fs&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;moduleName&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;argv&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt; &lt;span class="c1"&gt;// e.g., "users"&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;template&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;`
import { Test } from '@nestjs/testing';
import { &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nf"&gt;toPascalCase&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;moduleName&lt;/span&gt;&lt;span class="p"&gt;)}&lt;/span&gt;&lt;span class="s2"&gt;Service } from './&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;moduleName&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;.service';

describe('&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nf"&gt;toPascalCase&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;moduleName&lt;/span&gt;&lt;span class="p"&gt;)}&lt;/span&gt;&lt;span class="s2"&gt;Service', () =&amp;gt; {
  let service: &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nf"&gt;toPascalCase&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;moduleName&lt;/span&gt;&lt;span class="p"&gt;)}&lt;/span&gt;&lt;span class="s2"&gt;Service;

  beforeEach(async () =&amp;gt; {
    const module = await Test.createTestingModule({
      providers: [&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nf"&gt;toPascalCase&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;moduleName&lt;/span&gt;&lt;span class="p"&gt;)}&lt;/span&gt;&lt;span class="s2"&gt;Service]
    }).compile();
    service = module.get(&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nf"&gt;toPascalCase&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;moduleName&lt;/span&gt;&lt;span class="p"&gt;)}&lt;/span&gt;&lt;span class="s2"&gt;Service);
  });

  it('should be defined', () =&amp;gt; {
    expect(service).toBeDefined();
  });
});
`&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="nx"&gt;fs&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;writeFileSync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`src/&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;moduleName&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;/&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;moduleName&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;.service.spec.ts`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;template&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`✓ Test scaffold created: &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;moduleName&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;.service.spec.ts`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&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;"scripts"&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;"generate:test"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"ts-node scripts/generate-test.ts"&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;p&gt;Usage: &lt;code&gt;npm run generate:test users&lt;/code&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  Part 7 — Team Alignment &amp;amp; Standards
&lt;/h2&gt;

&lt;h3&gt;
  
  
  7.1 Developer Onboarding Doc (1-pager)
&lt;/h3&gt;

&lt;p&gt;Every new developer should receive this contract:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;TDD Contract — [Team Name]

1. No PR is merged without tests
2. Tests are written BEFORE implementation (or alongside for legacy)
3. Test naming: "should [behavior] when [condition]"
4. Pyramid ratio: 70% unit / 20% integration / 10% E2E
5. Coverage gate: 80% enforced in CI — PRs that drop coverage are blocked
6. Mocks: use jest.fn() / jest.spyOn() for external deps
7. Test data: use factory functions, never hardcoded magic values
8. AI-generated code must include AI-generated tests (use .cursorrules)
9. Failing tests in main branch = P0 incident
10. Review tests as carefully as implementation — they ARE documentation
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  7.2 PR Review Checklist for Tests
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;□ Does every new function have at least one test?
□ Are failure/error paths tested?
□ Are external deps properly mocked?
□ Do tests follow AAA pattern?
□ Are test descriptions meaningful (not "it works")?
□ Is there test data factory used (no magic strings)?
□ Does coverage remain above threshold?
□ Are integration tests using real DB (testcontainers) or proper mocks?
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  7.3 Test Factory Pattern (Team Standard)
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// test/factories/user.factory.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;faker&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;@faker-js/faker&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;createUserDto&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;overrides&lt;/span&gt; &lt;span class="o"&gt;=&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="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;faker&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="nf"&gt;uuid&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
  &lt;span class="na"&gt;email&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;faker&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;internet&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;email&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="nx"&gt;faker&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;person&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;fullName&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
  &lt;span class="na"&gt;createdAt&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Date&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
  &lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;overrides&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="c1"&gt;// Usage in tests:&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;user&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;createUserDto&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;email&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;specific@test.com&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Part 8 — Package Ecosystem Summary
&lt;/h2&gt;

&lt;h3&gt;
  
  
  JavaScript / TypeScript
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Package&lt;/th&gt;
&lt;th&gt;Purpose&lt;/th&gt;
&lt;th&gt;Verdict&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Jest&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Test runner + assertions&lt;/td&gt;
&lt;td&gt;Industry standard for Node/NestJS&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Vitest&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Vite-native test runner&lt;/td&gt;
&lt;td&gt;Preferred for React/Next.js/Vite&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Supertest&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;HTTP integration testing&lt;/td&gt;
&lt;td&gt;Standard for Express/NestJS&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;MSW&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;API mock server (browser + Node)&lt;/td&gt;
&lt;td&gt;Industry standard for React&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Testcontainers&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Real DB in Docker for tests&lt;/td&gt;
&lt;td&gt;Best for integration tests&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;@faker-js/faker&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Test data generation&lt;/td&gt;
&lt;td&gt;Standard&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;jest-mock-extended&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;TypeScript-aware auto-mocking&lt;/td&gt;
&lt;td&gt;Recommended for NestJS&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Pact.js&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Consumer-driven contract tests&lt;/td&gt;
&lt;td&gt;Microservices only&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Playwright&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;E2E browser testing&lt;/td&gt;
&lt;td&gt;Now preferred over Cypress&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Cypress&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;E2E browser testing&lt;/td&gt;
&lt;td&gt;Still strong, but Playwright winning&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

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

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Package&lt;/th&gt;
&lt;th&gt;Purpose&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;pytest&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Standard test runner&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;pytest-cov&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Coverage&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;pytest-asyncio&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Async test support&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;factory-boy&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Test data factories&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;respx / httpx&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;HTTP mocking for async&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;pytest-mock&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Mock integration&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

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

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Package&lt;/th&gt;
&lt;th&gt;Purpose&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Pest&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Modern test framework (recommended)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;PHPUnit&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Legacy but still supported&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Mockery&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Mocking&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Laravel Dusk&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Browser E2E&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;




&lt;h2&gt;
  
  
  Part 9 — What the Industry Is Doing Now
&lt;/h2&gt;

&lt;h3&gt;
  
  
  9.1 Current Trends (2024–2025)
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;AI-assisted test generation is mainstream now.&lt;/strong&gt; GitHub Copilot, Cursor, and Qodo are being used to scaffold tests. The shift is: AI writes first drafts, engineers review and enforce standards.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Vitest is winning in frontend.&lt;/strong&gt; For Vite-based projects (Vite + React, Next.js app router), Vitest is significantly faster than Jest due to native ESM support and Vite transform reuse.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Testcontainers adoption is rising.&lt;/strong&gt; Instead of mocking DB entirely, teams spin up real PostgreSQL/Redis/MongoDB containers in CI via Testcontainers. Tests are more realistic but still isolated.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Contract testing in microservices is growing.&lt;/strong&gt; Pact and Pactflow adoption is increasing as teams feel the pain of mismatched API contracts between services.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Playwright over Cypress for E2E.&lt;/strong&gt; Playwright's multi-browser support, built-in parallelism, and better CI performance has made it the new default.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Test coverage as a PR gate, not a metric.&lt;/strong&gt; Teams are moving away from tracking coverage as a KPI toward using it purely as a blocking threshold.&lt;/p&gt;

&lt;h3&gt;
  
  
  9.2 What Most Teams Actually Do
&lt;/h3&gt;

&lt;p&gt;Reality check — not everyone does pure TDD:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Approach&lt;/th&gt;
&lt;th&gt;Prevalence&lt;/th&gt;
&lt;th&gt;Notes&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Test-after (write code then test)&lt;/td&gt;
&lt;td&gt;~50% of teams&lt;/td&gt;
&lt;td&gt;Pragmatic, but riskier&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;TDD on critical paths only&lt;/td&gt;
&lt;td&gt;~30% of teams&lt;/td&gt;
&lt;td&gt;Balanced approach&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Pure TDD&lt;/td&gt;
&lt;td&gt;~10% of teams&lt;/td&gt;
&lt;td&gt;Often fintech, healthcare&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;No tests&lt;/td&gt;
&lt;td&gt;~10% of teams&lt;/td&gt;
&lt;td&gt;Startups pre-product-market-fit&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The &lt;strong&gt;pragmatic hybrid&lt;/strong&gt; is most common: TDD for services/domain logic, integration tests for DB layer, Playwright for critical user flows.&lt;/p&gt;




&lt;h2&gt;
  
  
  Part 10 — Future Scope and Roadmap
&lt;/h2&gt;

&lt;h3&gt;
  
  
  10.1 Your Adoption Plan
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Phase 1 — Foundation (Week 1–2)&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Configure Jest/Vitest per stack&lt;/li&gt;
&lt;li&gt;Set up coverage thresholds in CI&lt;/li&gt;
&lt;li&gt;Add pre-commit hooks (Husky + lint-staged)&lt;/li&gt;
&lt;li&gt;Create &lt;code&gt;.cursorrules&lt;/code&gt; with TDD prompt wrapper&lt;/li&gt;
&lt;li&gt;Create test factory templates per module&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Phase 2 — Culture (Week 3–4)&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;PR checklist enforcement&lt;/li&gt;
&lt;li&gt;Onboarding doc for new devs&lt;/li&gt;
&lt;li&gt;First "TDD session" — pair-program a feature end-to-end&lt;/li&gt;
&lt;li&gt;Retroactive coverage tracking for legacy modules&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Phase 3 — Automation (Month 2)&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Build test scaffold generator CLI&lt;/li&gt;
&lt;li&gt;Evaluate Qodo/CodiumAI for auto test gen&lt;/li&gt;
&lt;li&gt;Integrate Testcontainers for integration tests&lt;/li&gt;
&lt;li&gt;Add contract tests for any inter-service APIs&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Phase 4 — Maturity (Month 3+)&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Coverage reports in PR comments (via jest-coverage-comment action)&lt;/li&gt;
&lt;li&gt;Mutation testing with &lt;strong&gt;Stryker&lt;/strong&gt; (tests your tests)&lt;/li&gt;
&lt;li&gt;Test quality metrics (flakiness tracking, test execution time)&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  10.2 Mutation Testing (Advanced)
&lt;/h3&gt;

&lt;p&gt;Mutation testing checks if your tests are actually meaningful:&lt;br&gt;
&lt;/p&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; @stryker-mutator/core @stryker-mutator/jest-runner
npx stryker run
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Stryker introduces small bugs ("mutants") into your code and checks if your tests catch them. Mutation score &amp;gt; 70% means your tests have real value.&lt;/p&gt;




&lt;h2&gt;
  
  
  Appendix: Quick Reference
&lt;/h2&gt;

&lt;h3&gt;
  
  
  TDD Command Cheat Sheet
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# NestJS&lt;/span&gt;
npm run &lt;span class="nb"&gt;test&lt;/span&gt;              &lt;span class="c"&gt;# unit tests&lt;/span&gt;
npm run &lt;span class="nb"&gt;test&lt;/span&gt;:e2e          &lt;span class="c"&gt;# integration/e2e tests  &lt;/span&gt;
npm run &lt;span class="nb"&gt;test&lt;/span&gt;:cov          &lt;span class="c"&gt;# with coverage report&lt;/span&gt;

&lt;span class="c"&gt;# React/Next.js (Vitest)&lt;/span&gt;
npx vitest                &lt;span class="c"&gt;# watch mode&lt;/span&gt;
npx vitest run &lt;span class="nt"&gt;--coverage&lt;/span&gt; &lt;span class="c"&gt;# single run with coverage&lt;/span&gt;

&lt;span class="c"&gt;# Python&lt;/span&gt;
pytest tests/ &lt;span class="nt"&gt;-v&lt;/span&gt; &lt;span class="nt"&gt;--cov&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;app &lt;span class="nt"&gt;--cov-report&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;html

&lt;span class="c"&gt;# Laravel&lt;/span&gt;
php artisan &lt;span class="nb"&gt;test&lt;/span&gt; &lt;span class="nt"&gt;--coverage&lt;/span&gt;
./vendor/bin/pest &lt;span class="nt"&gt;--coverage&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Coverage Report Integration (GitHub Actions)
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&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;ArtiomTr/jest-coverage-report-action@v2&lt;/span&gt;
  &lt;span class="na"&gt;with&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;test-script&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;npm run test:cov&lt;/span&gt;
    &lt;span class="na"&gt;threshold&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;80&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;p&gt;&lt;em&gt;Guide maintained by engineering team. Update when packages release major versions or architectural patterns shift.&lt;/em&gt;&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Unit Test AI Guide — Zero Hallucination, Cross-Stack Standard</title>
      <dc:creator>Bhaumik</dc:creator>
      <pubDate>Tue, 23 Jun 2026 11:32:31 +0000</pubDate>
      <link>https://dev.to/bhaumik-viitor/unit-test-ai-guide-zero-hallucination-cross-stack-standard-4ac5</link>
      <guid>https://dev.to/bhaumik-viitor/unit-test-ai-guide-zero-hallucination-cross-stack-standard-4ac5</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Focus:&lt;/strong&gt; Unit Tests ONLY — no integration, no E2E&lt;br&gt;&lt;br&gt;
&lt;strong&gt;Stacks:&lt;/strong&gt; Node.js (NestJS/Express) · React.js · Python · Angular · Laravel&lt;br&gt;&lt;br&gt;
&lt;strong&gt;Goal:&lt;/strong&gt; AI generates unit tests consistently, deterministically, without hallucination&lt;br&gt;&lt;br&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;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Stack&lt;/th&gt;
&lt;th&gt;Library&lt;/th&gt;
&lt;th&gt;Why This One&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Node.js / NestJS / Express&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;Jest&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Native DI mocking, &lt;code&gt;@nestjs/testing&lt;/code&gt; built around it, widest ecosystem&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;React.js&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;Vitest&lt;/code&gt; + &lt;code&gt;@testing-library/react&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;Native Vite/ESM support, Jest-compatible API, 3–10x faster&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Python&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;pytest&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;De facto standard, fixture system eliminates boilerplate, best plugin ecosystem&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Angular&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;Jest&lt;/code&gt; (replace Karma)&lt;/td&gt;
&lt;td&gt;Karma is deprecated in Angular 17+; Jest is the official migration target&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Laravel&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;Pest&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Modern syntax, built on PHPUnit, higher signal-to-noise ratio&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&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;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Capability&lt;/th&gt;
&lt;th&gt;Cursor&lt;/th&gt;
&lt;th&gt;VS Code + Copilot&lt;/th&gt;
&lt;th&gt;WebStorm&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Project-level AI rules&lt;/td&gt;
&lt;td&gt;✅ &lt;code&gt;.cursor/rules/&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Codebase-aware context&lt;/td&gt;
&lt;td&gt;✅ &lt;code&gt;@codebase&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;Partial&lt;/td&gt;
&lt;td&gt;Partial&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Run terminal + read output&lt;/td&gt;
&lt;td&gt;✅ Composer&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Multi-file generation&lt;/td&gt;
&lt;td&gt;✅ Agent mode&lt;/td&gt;
&lt;td&gt;Limited&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Custom instructions per filetype&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;MCP server integration&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&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="nn"&gt;---&lt;/span&gt;
&lt;span class="na"&gt;description&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Global unit test rules — applies to all files in this project&lt;/span&gt;
&lt;span class="na"&gt;globs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;**/*.spec.ts"&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;**/*.test.ts"&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;**/*.spec.tsx"&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;**/*_test.py"&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;**/Test*.php"&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;
&lt;span class="na"&gt;alwaysApply&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
&lt;span class="nn"&gt;---&lt;/span&gt;

&lt;span class="gh"&gt;# Unit Test Contract — MUST FOLLOW, NO EXCEPTIONS&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="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;br&gt;
// Act — call the single function/method under test&lt;br&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="nn"&gt;---&lt;/span&gt;
&lt;span class="na"&gt;description&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;NestJS unit test rules&lt;/span&gt;
&lt;span class="na"&gt;globs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;src/**/*.service.ts"&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;src/**/*.guard.ts"&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;src/**/*.interceptor.ts"&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;src/**/*.pipe.ts"&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;
&lt;span class="nn"&gt;---&lt;/span&gt;

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

&lt;span class="gu"&gt;## Library: Jest + @nestjs/testing + jest-mock-extended&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;br&gt;
const module = await Test.createTestingModule({&lt;br&gt;
  providers: [&lt;br&gt;
    SubjectService,&lt;br&gt;
    { provide: DependencyService, useValue: mockDependency }&lt;br&gt;
  ]&lt;br&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;br&gt;
import { createMock } from '@golevelup/ts-jest';&lt;br&gt;
// OR&lt;br&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;br&gt;
const mockRepo = {&lt;br&gt;
  findOne: jest.fn(),&lt;br&gt;
  save: jest.fn(),&lt;br&gt;
  delete: jest.fn(),&lt;br&gt;
  findAll: jest.fn(),&lt;br&gt;
  update: jest.fn(),&lt;br&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;br&gt;
import { Test, TestingModule } from '@nestjs/testing';&lt;br&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="nn"&gt;---&lt;/span&gt;
&lt;span class="na"&gt;description&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;React unit test rules&lt;/span&gt;
&lt;span class="na"&gt;globs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;src/**/*.tsx"&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;src/**/*.component.tsx"&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;src/hooks/**/*.ts"&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;
&lt;span class="nn"&gt;---&lt;/span&gt;

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

&lt;span class="gu"&gt;## Library: Vitest + @testing-library/react + @testing-library/user-event&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;br&gt;
export default defineConfig({&lt;br&gt;
  test: {&lt;br&gt;
    environment: 'jsdom',&lt;br&gt;
    globals: true,&lt;br&gt;
    setupFiles: ['./src/test/setup.ts']&lt;br&gt;
  }&lt;br&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;br&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;br&gt;
import { render, screen } from '@testing-library/react';&lt;br&gt;
import userEvent from '@testing-library/user-event';&lt;br&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;br&gt;
const user = userEvent.setup();&lt;br&gt;
await user.click(button);&lt;br&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;br&gt;
import { renderHook, act } from '@testing-library/react';&lt;br&gt;
const { result } = renderHook(() =&amp;gt; useMyHook());&lt;br&gt;
act(() =&amp;gt; result.current.doSomething());&lt;br&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;
markdown&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="nn"&gt;---&lt;/span&gt;
&lt;span class="na"&gt;description&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Python unit test rules&lt;/span&gt;
&lt;span class="na"&gt;globs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;**/*.py"&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;!**/*migrations*"&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;
&lt;span class="nn"&gt;---&lt;/span&gt;

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

&lt;span class="gu"&gt;## Library: pytest + pytest-mock + factory-boy&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="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;br&gt;
    def &lt;strong&gt;init&lt;/strong&gt;(self, repo: UserRepository):&lt;br&gt;
        self.repo = repo&lt;/p&gt;
&lt;h1&gt;
  
  
  BAD — untestable
&lt;/h1&gt;

&lt;p&gt;class UserService:&lt;br&gt;
    def &lt;strong&gt;init&lt;/strong&gt;(self):&lt;br&gt;
        self.repo = UserRepository()  # can't mock this&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 — pytest-mock (mocker fixture)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;&lt;br&gt;
python&lt;br&gt;
def test_raises_when_user_not_found(mocker):&lt;br&gt;
    mock_repo = mocker.Mock()&lt;br&gt;
    mock_repo.find_by_id.return_value = None&lt;br&gt;
    service = UserService(mock_repo)&lt;br&gt;
    with pytest.raises(UserNotFoundException):&lt;br&gt;
        service.get_user("missing-id")&lt;br&gt;
&lt;/p&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;br&gt;
import pytest&lt;/p&gt;

&lt;p&gt;@pytest.mark.asyncio&lt;br&gt;
async def test_async_service(mocker):&lt;br&gt;
    mock_repo = mocker.AsyncMock()&lt;br&gt;
    ...&lt;br&gt;
&lt;/p&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;br&gt;
@pytest.fixture&lt;br&gt;
def user_service(mocker):&lt;br&gt;
    repo = mocker.Mock()&lt;br&gt;
    return UserService(repo), repo&lt;/p&gt;

&lt;p&gt;def test_get_user_happy_path(user_service):&lt;br&gt;
    service, repo = user_service&lt;br&gt;
    repo.find_by_id.return_value = User(id="1", email="&lt;a href="mailto:a@b.com"&gt;a@b.com&lt;/a&gt;")&lt;br&gt;
    result = service.get_user("1")&lt;br&gt;
    assert result.email == "&lt;a href="mailto:a@b.com"&gt;a@b.com&lt;/a&gt;"&lt;br&gt;
&lt;/p&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;
shell&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="nn"&gt;---&lt;/span&gt;
&lt;span class="na"&gt;description&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Angular unit test rules&lt;/span&gt;
&lt;span class="na"&gt;globs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;src/app/**/*.component.ts"&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;src/app/**/*.service.ts"&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;src/app/**/*.pipe.ts"&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;src/app/**/*.guard.ts"&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;
&lt;span class="nn"&gt;---&lt;/span&gt;

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

&lt;span class="gu"&gt;## Library: Jest (NOT Karma — Karma is deprecated Angular 17+)&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;br&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;br&gt;
await TestBed.configureTestingModule({&lt;br&gt;
  imports: [ComponentUnderTest],  // standalone components&lt;br&gt;
  providers: [&lt;br&gt;
    { provide: UserService, useValue: mockUserService }&lt;br&gt;
  ]&lt;br&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;br&gt;
const mockUserService = {&lt;br&gt;
  getUser: jest.fn(),&lt;br&gt;
  createUser: jest.fn(),&lt;br&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;br&gt;
fixture.detectChanges(); // trigger ngOnInit&lt;br&gt;
const button = fixture.debugElement.query(By.css('[data-testid="submit"]'));&lt;br&gt;
button.nativeElement.click();&lt;br&gt;
fixture.detectChanges();&lt;br&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;br&gt;
it('should transform date correctly', () =&amp;gt; {&lt;br&gt;
  const pipe = new DateFormatPipe();&lt;br&gt;
  expect(pipe.transform(new Date('2024-01-01'))).toBe('Jan 1, 2024');&lt;br&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;br&gt;
const guard = TestBed.inject(AuthGuard);&lt;br&gt;
const result = await guard.canActivate(mockRoute, mockState);&lt;br&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;
php&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="nn"&gt;---&lt;/span&gt;
&lt;span class="na"&gt;description&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Laravel unit test rules&lt;/span&gt;
&lt;span class="na"&gt;globs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;app/Services/**/*.php"&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;app/Models/**/*.php"&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;app/Http/Requests/**/*.php"&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;app/Actions/**/*.php"&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;
&lt;span class="nn"&gt;---&lt;/span&gt;

&lt;span class="gh"&gt;# Laravel Unit Test Rules&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="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;br&gt;
class UserService {&lt;br&gt;
    public function __construct(&lt;br&gt;
        private readonly UserRepositoryInterface $repo&lt;br&gt;
    ) {}&lt;br&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;br&gt;
it('throws exception when user not found', function () {&lt;br&gt;
    // Arrange&lt;br&gt;
    $repo = Mockery::mock(UserRepositoryInterface::class);&lt;br&gt;
    $repo-&amp;gt;shouldReceive('findById')-&amp;gt;once()-&amp;gt;andReturn(null);&lt;br&gt;
    $service = new UserService($repo);&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// 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;br&gt;
it('validates email format', function (string $email, bool $valid) {&lt;br&gt;
    expect(validateEmail($email))-&amp;gt;toBe($valid);&lt;br&gt;
})-&amp;gt;with([&lt;br&gt;
    ['&lt;a href="mailto:valid@email.com"&gt;valid@email.com&lt;/a&gt;', true],&lt;br&gt;
    ['notanemail', false],&lt;br&gt;
    ['', false],&lt;br&gt;
    ['@nodomain.com', false],&lt;br&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="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="gu"&gt;## Unit Test Rules — NON-NEGOTIABLE&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="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="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="gu"&gt;### Coverage target: 80% lines, 75% branches per module&lt;/span&gt;

&lt;span class="gu"&gt;## Project Structure Reference&lt;/span&gt;
src/
  modules/
    users/
      users.service.ts
      users.service.spec.ts   ← unit test lives here
      users.repository.ts
      users.repository.spec.ts
&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;Scope: E2E only — not relevant for unit tests&lt;/li&gt;
&lt;li&gt;Skip for this use case&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;Gives Claude access to project files&lt;/li&gt;
&lt;li&gt;Use in Claude Desktop to read source → generate tests&lt;/li&gt;
&lt;li&gt;Install: configured in &lt;code&gt;claude_desktop_config.json&lt;/code&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;Reads a source file&lt;/li&gt;
&lt;li&gt;Extracts function signatures + types&lt;/li&gt;
&lt;li&gt;Returns structured JSON to Claude&lt;/li&gt;
&lt;li&gt;Claude generates tests from structure, not guesswork
&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="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="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 plaintext"&gt;&lt;code&gt;Generate a unit test file for this [NestJS service / React component / Python class / Angular service / Laravel service].

Rules:
- Library: [Jest / Vitest / pytest / Jest / Pest]
- Test only THIS file — no integration
- Mock ALL dependencies listed in the constructor/props
- Follow AAA pattern with comments
- Minimum 4 test cases per public method
- Use ONLY methods/properties that exist in this source file
- Do NOT import anything not shown in the source
- Naming: "should [behavior] when [condition]"
&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 plaintext"&gt;&lt;code&gt;Read [filename].
Extract:
1. Class/function name
2. All public methods with parameter types and return types
3. All constructor dependencies (for mocking)

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 plaintext"&gt;&lt;code&gt;For each file in [directory], generate a corresponding .spec.ts file.
Process one file at a time.
For each file:
  1. Read the source
  2. List the public methods you found (confirm before generating)
  3. Generate the test file
  4. Show the test file path

Do not proceed to the next file until the current one is confirmed.
&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 plaintext"&gt;&lt;code&gt;src/
  modules/
    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;/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="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>unittests</category>
      <category>testing</category>
      <category>cursor</category>
      <category>pytest</category>
    </item>
    <item>
      <title>Unit Test AI Guide — Zero Hallucination, Cross-Stack Standard</title>
      <dc:creator>Bhaumik</dc:creator>
      <pubDate>Tue, 23 Jun 2026 10:41:05 +0000</pubDate>
      <link>https://dev.to/bhaumik-viitor/unit-test-ai-guide-zero-hallucination-cross-stack-standard-4c8a</link>
      <guid>https://dev.to/bhaumik-viitor/unit-test-ai-guide-zero-hallucination-cross-stack-standard-4c8a</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Focus:&lt;/strong&gt; Unit Tests ONLY — no integration, no E2E&lt;br&gt;&lt;br&gt;
&lt;strong&gt;Stacks:&lt;/strong&gt; Node.js (NestJS/Express) · React.js · Python · Angular · Laravel&lt;br&gt;&lt;br&gt;
&lt;strong&gt;Goal:&lt;/strong&gt; AI generates unit tests consistently, deterministically, without hallucination&lt;br&gt;&lt;br&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;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Stack&lt;/th&gt;
&lt;th&gt;Library&lt;/th&gt;
&lt;th&gt;Why This One&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Node.js / NestJS / Express&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;Jest&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Native DI mocking, &lt;code&gt;@nestjs/testing&lt;/code&gt; built around it, widest ecosystem&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;React.js&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;Vitest&lt;/code&gt; + &lt;code&gt;@testing-library/react&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;Native Vite/ESM support, Jest-compatible API, 3–10x faster&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Python&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;pytest&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;De facto standard, fixture system eliminates boilerplate, best plugin ecosystem&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Angular&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;Jest&lt;/code&gt; (replace Karma)&lt;/td&gt;
&lt;td&gt;Karma is deprecated in Angular 17+; Jest is the official migration target&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Laravel&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;Pest&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Modern syntax, built on PHPUnit, higher signal-to-noise ratio&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&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;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Capability&lt;/th&gt;
&lt;th&gt;Cursor&lt;/th&gt;
&lt;th&gt;VS Code + Copilot&lt;/th&gt;
&lt;th&gt;WebStorm&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Project-level AI rules&lt;/td&gt;
&lt;td&gt;✅ &lt;code&gt;.cursor/rules/&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Codebase-aware context&lt;/td&gt;
&lt;td&gt;✅ &lt;code&gt;@codebase&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;Partial&lt;/td&gt;
&lt;td&gt;Partial&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Run terminal + read output&lt;/td&gt;
&lt;td&gt;✅ Composer&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Multi-file generation&lt;/td&gt;
&lt;td&gt;✅ Agent mode&lt;/td&gt;
&lt;td&gt;Limited&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Custom instructions per filetype&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;MCP server integration&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&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="nn"&gt;---&lt;/span&gt;
&lt;span class="na"&gt;description&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Global unit test rules — applies to all files in this project&lt;/span&gt;
&lt;span class="na"&gt;globs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;**/*.spec.ts"&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;**/*.test.ts"&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;**/*.spec.tsx"&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;**/*_test.py"&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;**/Test*.php"&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;
&lt;span class="na"&gt;alwaysApply&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
&lt;span class="nn"&gt;---&lt;/span&gt;

&lt;span class="gh"&gt;# Unit Test Contract — MUST FOLLOW, NO EXCEPTIONS&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="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;br&gt;
// Act — call the single function/method under test&lt;br&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="nn"&gt;---&lt;/span&gt;
&lt;span class="na"&gt;description&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;NestJS unit test rules&lt;/span&gt;
&lt;span class="na"&gt;globs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;src/**/*.service.ts"&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;src/**/*.guard.ts"&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;src/**/*.interceptor.ts"&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;src/**/*.pipe.ts"&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;
&lt;span class="nn"&gt;---&lt;/span&gt;

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

&lt;span class="gu"&gt;## Library: Jest + @nestjs/testing + jest-mock-extended&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;br&gt;
const module = await Test.createTestingModule({&lt;br&gt;
  providers: [&lt;br&gt;
    SubjectService,&lt;br&gt;
    { provide: DependencyService, useValue: mockDependency }&lt;br&gt;
  ]&lt;br&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;br&gt;
import { createMock } from '@golevelup/ts-jest';&lt;br&gt;
// OR&lt;br&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;br&gt;
const mockRepo = {&lt;br&gt;
  findOne: jest.fn(),&lt;br&gt;
  save: jest.fn(),&lt;br&gt;
  delete: jest.fn(),&lt;br&gt;
  findAll: jest.fn(),&lt;br&gt;
  update: jest.fn(),&lt;br&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;br&gt;
import { Test, TestingModule } from '@nestjs/testing';&lt;br&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="nn"&gt;---&lt;/span&gt;
&lt;span class="na"&gt;description&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;React unit test rules&lt;/span&gt;
&lt;span class="na"&gt;globs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;src/**/*.tsx"&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;src/**/*.component.tsx"&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;src/hooks/**/*.ts"&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;
&lt;span class="nn"&gt;---&lt;/span&gt;

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

&lt;span class="gu"&gt;## Library: Vitest + @testing-library/react + @testing-library/user-event&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;br&gt;
export default defineConfig({&lt;br&gt;
  test: {&lt;br&gt;
    environment: 'jsdom',&lt;br&gt;
    globals: true,&lt;br&gt;
    setupFiles: ['./src/test/setup.ts']&lt;br&gt;
  }&lt;br&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;br&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;br&gt;
import { render, screen } from '@testing-library/react';&lt;br&gt;
import userEvent from '@testing-library/user-event';&lt;br&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;br&gt;
const user = userEvent.setup();&lt;br&gt;
await user.click(button);&lt;br&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;br&gt;
import { renderHook, act } from '@testing-library/react';&lt;br&gt;
const { result } = renderHook(() =&amp;gt; useMyHook());&lt;br&gt;
act(() =&amp;gt; result.current.doSomething());&lt;br&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;
markdown&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="nn"&gt;---&lt;/span&gt;
&lt;span class="na"&gt;description&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Python unit test rules&lt;/span&gt;
&lt;span class="na"&gt;globs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;**/*.py"&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;!**/*migrations*"&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;
&lt;span class="nn"&gt;---&lt;/span&gt;

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

&lt;span class="gu"&gt;## Library: pytest + pytest-mock + factory-boy&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="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;br&gt;
    def &lt;strong&gt;init&lt;/strong&gt;(self, repo: UserRepository):&lt;br&gt;
        self.repo = repo&lt;/p&gt;
&lt;h1&gt;
  
  
  BAD — untestable
&lt;/h1&gt;

&lt;p&gt;class UserService:&lt;br&gt;
    def &lt;strong&gt;init&lt;/strong&gt;(self):&lt;br&gt;
        self.repo = UserRepository()  # can't mock this&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 — pytest-mock (mocker fixture)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;&lt;br&gt;
python&lt;br&gt;
def test_raises_when_user_not_found(mocker):&lt;br&gt;
    mock_repo = mocker.Mock()&lt;br&gt;
    mock_repo.find_by_id.return_value = None&lt;br&gt;
    service = UserService(mock_repo)&lt;br&gt;
    with pytest.raises(UserNotFoundException):&lt;br&gt;
        service.get_user("missing-id")&lt;br&gt;
&lt;/p&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;br&gt;
import pytest&lt;/p&gt;

&lt;p&gt;@pytest.mark.asyncio&lt;br&gt;
async def test_async_service(mocker):&lt;br&gt;
    mock_repo = mocker.AsyncMock()&lt;br&gt;
    ...&lt;br&gt;
&lt;/p&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;br&gt;
@pytest.fixture&lt;br&gt;
def user_service(mocker):&lt;br&gt;
    repo = mocker.Mock()&lt;br&gt;
    return UserService(repo), repo&lt;/p&gt;

&lt;p&gt;def test_get_user_happy_path(user_service):&lt;br&gt;
    service, repo = user_service&lt;br&gt;
    repo.find_by_id.return_value = User(id="1", email="&lt;a href="mailto:a@b.com"&gt;a@b.com&lt;/a&gt;")&lt;br&gt;
    result = service.get_user("1")&lt;br&gt;
    assert result.email == "&lt;a href="mailto:a@b.com"&gt;a@b.com&lt;/a&gt;"&lt;br&gt;
&lt;/p&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;
shell&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="nn"&gt;---&lt;/span&gt;
&lt;span class="na"&gt;description&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Angular unit test rules&lt;/span&gt;
&lt;span class="na"&gt;globs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;src/app/**/*.component.ts"&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;src/app/**/*.service.ts"&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;src/app/**/*.pipe.ts"&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;src/app/**/*.guard.ts"&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;
&lt;span class="nn"&gt;---&lt;/span&gt;

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

&lt;span class="gu"&gt;## Library: Jest (NOT Karma — Karma is deprecated Angular 17+)&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;br&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;br&gt;
await TestBed.configureTestingModule({&lt;br&gt;
  imports: [ComponentUnderTest],  // standalone components&lt;br&gt;
  providers: [&lt;br&gt;
    { provide: UserService, useValue: mockUserService }&lt;br&gt;
  ]&lt;br&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;br&gt;
const mockUserService = {&lt;br&gt;
  getUser: jest.fn(),&lt;br&gt;
  createUser: jest.fn(),&lt;br&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;br&gt;
fixture.detectChanges(); // trigger ngOnInit&lt;br&gt;
const button = fixture.debugElement.query(By.css('[data-testid="submit"]'));&lt;br&gt;
button.nativeElement.click();&lt;br&gt;
fixture.detectChanges();&lt;br&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;br&gt;
it('should transform date correctly', () =&amp;gt; {&lt;br&gt;
  const pipe = new DateFormatPipe();&lt;br&gt;
  expect(pipe.transform(new Date('2024-01-01'))).toBe('Jan 1, 2024');&lt;br&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;br&gt;
const guard = TestBed.inject(AuthGuard);&lt;br&gt;
const result = await guard.canActivate(mockRoute, mockState);&lt;br&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;
php&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="nn"&gt;---&lt;/span&gt;
&lt;span class="na"&gt;description&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Laravel unit test rules&lt;/span&gt;
&lt;span class="na"&gt;globs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;app/Services/**/*.php"&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;app/Models/**/*.php"&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;app/Http/Requests/**/*.php"&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;app/Actions/**/*.php"&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;
&lt;span class="nn"&gt;---&lt;/span&gt;

&lt;span class="gh"&gt;# Laravel Unit Test Rules&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="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;br&gt;
class UserService {&lt;br&gt;
    public function __construct(&lt;br&gt;
        private readonly UserRepositoryInterface $repo&lt;br&gt;
    ) {}&lt;br&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;br&gt;
it('throws exception when user not found', function () {&lt;br&gt;
    // Arrange&lt;br&gt;
    $repo = Mockery::mock(UserRepositoryInterface::class);&lt;br&gt;
    $repo-&amp;gt;shouldReceive('findById')-&amp;gt;once()-&amp;gt;andReturn(null);&lt;br&gt;
    $service = new UserService($repo);&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// 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;br&gt;
it('validates email format', function (string $email, bool $valid) {&lt;br&gt;
    expect(validateEmail($email))-&amp;gt;toBe($valid);&lt;br&gt;
})-&amp;gt;with([&lt;br&gt;
    ['&lt;a href="mailto:valid@email.com"&gt;valid@email.com&lt;/a&gt;', true],&lt;br&gt;
    ['notanemail', false],&lt;br&gt;
    ['', false],&lt;br&gt;
    ['@nodomain.com', false],&lt;br&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="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="gu"&gt;## Unit Test Rules — NON-NEGOTIABLE&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="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="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="gu"&gt;### Coverage target: 80% lines, 75% branches per module&lt;/span&gt;

&lt;span class="gu"&gt;## Project Structure Reference&lt;/span&gt;
src/
  modules/
    users/
      users.service.ts
      users.service.spec.ts   ← unit test lives here
      users.repository.ts
      users.repository.spec.ts
&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;Scope: E2E only — not relevant for unit tests&lt;/li&gt;
&lt;li&gt;Skip for this use case&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;Gives Claude access to project files&lt;/li&gt;
&lt;li&gt;Use in Claude Desktop to read source → generate tests&lt;/li&gt;
&lt;li&gt;Install: configured in &lt;code&gt;claude_desktop_config.json&lt;/code&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;Reads a source file&lt;/li&gt;
&lt;li&gt;Extracts function signatures + types&lt;/li&gt;
&lt;li&gt;Returns structured JSON to Claude&lt;/li&gt;
&lt;li&gt;Claude generates tests from structure, not guesswork
&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="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="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 plaintext"&gt;&lt;code&gt;Generate a unit test file for this [NestJS service / React component / Python class / Angular service / Laravel service].

Rules:
- Library: [Jest / Vitest / pytest / Jest / Pest]
- Test only THIS file — no integration
- Mock ALL dependencies listed in the constructor/props
- Follow AAA pattern with comments
- Minimum 4 test cases per public method
- Use ONLY methods/properties that exist in this source file
- Do NOT import anything not shown in the source
- Naming: "should [behavior] when [condition]"
&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 plaintext"&gt;&lt;code&gt;Read [filename].
Extract:
1. Class/function name
2. All public methods with parameter types and return types
3. All constructor dependencies (for mocking)

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 plaintext"&gt;&lt;code&gt;For each file in [directory], generate a corresponding .spec.ts file.
Process one file at a time.
For each file:
  1. Read the source
  2. List the public methods you found (confirm before generating)
  3. Generate the test file
  4. Show the test file path

Do not proceed to the next file until the current one is confirmed.
&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 plaintext"&gt;&lt;code&gt;src/
  modules/
    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;/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="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>unittests</category>
      <category>testing</category>
      <category>cursor</category>
      <category>pytest</category>
    </item>
    <item>
      <title>Unit Test AI Guide — Zero Hallucination, Cross-Stack Standard</title>
      <dc:creator>Bhaumik</dc:creator>
      <pubDate>Tue, 23 Jun 2026 10:23:07 +0000</pubDate>
      <link>https://dev.to/bhaumik-viitor/unit-test-ai-guide-zero-hallucination-cross-stack-standard-3o8e</link>
      <guid>https://dev.to/bhaumik-viitor/unit-test-ai-guide-zero-hallucination-cross-stack-standard-3o8e</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Focus:&lt;/strong&gt; Unit Tests ONLY — no integration, no E2E&lt;br&gt;&lt;br&gt;
&lt;strong&gt;Stacks:&lt;/strong&gt; Node.js (NestJS/Express) · React.js · Python · Angular · Laravel&lt;br&gt;&lt;br&gt;
&lt;strong&gt;Goal:&lt;/strong&gt; AI generates unit tests consistently, deterministically, without hallucination&lt;br&gt;&lt;br&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;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Stack&lt;/th&gt;
&lt;th&gt;Library&lt;/th&gt;
&lt;th&gt;Why This One&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Node.js / NestJS / Express&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;Jest&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Native DI mocking, &lt;code&gt;@nestjs/testing&lt;/code&gt; built around it, widest ecosystem&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;React.js&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;Vitest&lt;/code&gt; + &lt;code&gt;@testing-library/react&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;Native Vite/ESM support, Jest-compatible API, 3–10x faster&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Python&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;pytest&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;De facto standard, fixture system eliminates boilerplate, best plugin ecosystem&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Angular&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;Jest&lt;/code&gt; (replace Karma)&lt;/td&gt;
&lt;td&gt;Karma is deprecated in Angular 17+; Jest is the official migration target&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Laravel&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;Pest&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Modern syntax, built on PHPUnit, higher signal-to-noise ratio&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&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;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Capability&lt;/th&gt;
&lt;th&gt;Cursor&lt;/th&gt;
&lt;th&gt;VS Code + Copilot&lt;/th&gt;
&lt;th&gt;WebStorm&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Project-level AI rules&lt;/td&gt;
&lt;td&gt;✅ &lt;code&gt;.cursor/rules/&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Codebase-aware context&lt;/td&gt;
&lt;td&gt;✅ &lt;code&gt;@codebase&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;Partial&lt;/td&gt;
&lt;td&gt;Partial&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Run terminal + read output&lt;/td&gt;
&lt;td&gt;✅ Composer&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Multi-file generation&lt;/td&gt;
&lt;td&gt;✅ Agent mode&lt;/td&gt;
&lt;td&gt;Limited&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Custom instructions per filetype&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;MCP server integration&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&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="nn"&gt;---&lt;/span&gt;
&lt;span class="na"&gt;description&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Global unit test rules — applies to all files in this project&lt;/span&gt;
&lt;span class="na"&gt;globs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;**/*.spec.ts"&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;**/*.test.ts"&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;**/*.spec.tsx"&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;**/*_test.py"&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;**/Test*.php"&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;
&lt;span class="na"&gt;alwaysApply&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
&lt;span class="nn"&gt;---&lt;/span&gt;

&lt;span class="gh"&gt;# Unit Test Contract — MUST FOLLOW, NO EXCEPTIONS&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="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;br&gt;
// Act — call the single function/method under test&lt;br&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="nn"&gt;---&lt;/span&gt;
&lt;span class="na"&gt;description&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;NestJS unit test rules&lt;/span&gt;
&lt;span class="na"&gt;globs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;src/**/*.service.ts"&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;src/**/*.guard.ts"&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;src/**/*.interceptor.ts"&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;src/**/*.pipe.ts"&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;
&lt;span class="nn"&gt;---&lt;/span&gt;

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

&lt;span class="gu"&gt;## Library: Jest + @nestjs/testing + jest-mock-extended&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;br&gt;
const module = await Test.createTestingModule({&lt;br&gt;
  providers: [&lt;br&gt;
    SubjectService,&lt;br&gt;
    { provide: DependencyService, useValue: mockDependency }&lt;br&gt;
  ]&lt;br&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;br&gt;
import { createMock } from '@golevelup/ts-jest';&lt;br&gt;
// OR&lt;br&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;br&gt;
const mockRepo = {&lt;br&gt;
  findOne: jest.fn(),&lt;br&gt;
  save: jest.fn(),&lt;br&gt;
  delete: jest.fn(),&lt;br&gt;
  findAll: jest.fn(),&lt;br&gt;
  update: jest.fn(),&lt;br&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;br&gt;
import { Test, TestingModule } from '@nestjs/testing';&lt;br&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="nn"&gt;---&lt;/span&gt;
&lt;span class="na"&gt;description&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;React unit test rules&lt;/span&gt;
&lt;span class="na"&gt;globs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;src/**/*.tsx"&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;src/**/*.component.tsx"&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;src/hooks/**/*.ts"&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;
&lt;span class="nn"&gt;---&lt;/span&gt;

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

&lt;span class="gu"&gt;## Library: Vitest + @testing-library/react + @testing-library/user-event&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;br&gt;
export default defineConfig({&lt;br&gt;
  test: {&lt;br&gt;
    environment: 'jsdom',&lt;br&gt;
    globals: true,&lt;br&gt;
    setupFiles: ['./src/test/setup.ts']&lt;br&gt;
  }&lt;br&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;br&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;br&gt;
import { render, screen } from '@testing-library/react';&lt;br&gt;
import userEvent from '@testing-library/user-event';&lt;br&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;br&gt;
const user = userEvent.setup();&lt;br&gt;
await user.click(button);&lt;br&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;br&gt;
import { renderHook, act } from '@testing-library/react';&lt;br&gt;
const { result } = renderHook(() =&amp;gt; useMyHook());&lt;br&gt;
act(() =&amp;gt; result.current.doSomething());&lt;br&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;
markdown&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="nn"&gt;---&lt;/span&gt;
&lt;span class="na"&gt;description&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Python unit test rules&lt;/span&gt;
&lt;span class="na"&gt;globs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;**/*.py"&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;!**/*migrations*"&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;
&lt;span class="nn"&gt;---&lt;/span&gt;

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

&lt;span class="gu"&gt;## Library: pytest + pytest-mock + factory-boy&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="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;br&gt;
    def &lt;strong&gt;init&lt;/strong&gt;(self, repo: UserRepository):&lt;br&gt;
        self.repo = repo&lt;/p&gt;
&lt;h1&gt;
  
  
  BAD — untestable
&lt;/h1&gt;

&lt;p&gt;class UserService:&lt;br&gt;
    def &lt;strong&gt;init&lt;/strong&gt;(self):&lt;br&gt;
        self.repo = UserRepository()  # can't mock this&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 — pytest-mock (mocker fixture)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;&lt;br&gt;
python&lt;br&gt;
def test_raises_when_user_not_found(mocker):&lt;br&gt;
    mock_repo = mocker.Mock()&lt;br&gt;
    mock_repo.find_by_id.return_value = None&lt;br&gt;
    service = UserService(mock_repo)&lt;br&gt;
    with pytest.raises(UserNotFoundException):&lt;br&gt;
        service.get_user("missing-id")&lt;br&gt;
&lt;/p&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;br&gt;
import pytest&lt;/p&gt;

&lt;p&gt;@pytest.mark.asyncio&lt;br&gt;
async def test_async_service(mocker):&lt;br&gt;
    mock_repo = mocker.AsyncMock()&lt;br&gt;
    ...&lt;br&gt;
&lt;/p&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;br&gt;
@pytest.fixture&lt;br&gt;
def user_service(mocker):&lt;br&gt;
    repo = mocker.Mock()&lt;br&gt;
    return UserService(repo), repo&lt;/p&gt;

&lt;p&gt;def test_get_user_happy_path(user_service):&lt;br&gt;
    service, repo = user_service&lt;br&gt;
    repo.find_by_id.return_value = User(id="1", email="&lt;a href="mailto:a@b.com"&gt;a@b.com&lt;/a&gt;")&lt;br&gt;
    result = service.get_user("1")&lt;br&gt;
    assert result.email == "&lt;a href="mailto:a@b.com"&gt;a@b.com&lt;/a&gt;"&lt;br&gt;
&lt;/p&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;
shell&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="nn"&gt;---&lt;/span&gt;
&lt;span class="na"&gt;description&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Angular unit test rules&lt;/span&gt;
&lt;span class="na"&gt;globs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;src/app/**/*.component.ts"&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;src/app/**/*.service.ts"&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;src/app/**/*.pipe.ts"&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;src/app/**/*.guard.ts"&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;
&lt;span class="nn"&gt;---&lt;/span&gt;

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

&lt;span class="gu"&gt;## Library: Jest (NOT Karma — Karma is deprecated Angular 17+)&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;br&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;br&gt;
await TestBed.configureTestingModule({&lt;br&gt;
  imports: [ComponentUnderTest],  // standalone components&lt;br&gt;
  providers: [&lt;br&gt;
    { provide: UserService, useValue: mockUserService }&lt;br&gt;
  ]&lt;br&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;br&gt;
const mockUserService = {&lt;br&gt;
  getUser: jest.fn(),&lt;br&gt;
  createUser: jest.fn(),&lt;br&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;br&gt;
fixture.detectChanges(); // trigger ngOnInit&lt;br&gt;
const button = fixture.debugElement.query(By.css('[data-testid="submit"]'));&lt;br&gt;
button.nativeElement.click();&lt;br&gt;
fixture.detectChanges();&lt;br&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;br&gt;
it('should transform date correctly', () =&amp;gt; {&lt;br&gt;
  const pipe = new DateFormatPipe();&lt;br&gt;
  expect(pipe.transform(new Date('2024-01-01'))).toBe('Jan 1, 2024');&lt;br&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;br&gt;
const guard = TestBed.inject(AuthGuard);&lt;br&gt;
const result = await guard.canActivate(mockRoute, mockState);&lt;br&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;
php&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="nn"&gt;---&lt;/span&gt;
&lt;span class="na"&gt;description&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Laravel unit test rules&lt;/span&gt;
&lt;span class="na"&gt;globs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;app/Services/**/*.php"&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;app/Models/**/*.php"&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;app/Http/Requests/**/*.php"&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;app/Actions/**/*.php"&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;
&lt;span class="nn"&gt;---&lt;/span&gt;

&lt;span class="gh"&gt;# Laravel Unit Test Rules&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="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;br&gt;
class UserService {&lt;br&gt;
    public function __construct(&lt;br&gt;
        private readonly UserRepositoryInterface $repo&lt;br&gt;
    ) {}&lt;br&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;br&gt;
it('throws exception when user not found', function () {&lt;br&gt;
    // Arrange&lt;br&gt;
    $repo = Mockery::mock(UserRepositoryInterface::class);&lt;br&gt;
    $repo-&amp;gt;shouldReceive('findById')-&amp;gt;once()-&amp;gt;andReturn(null);&lt;br&gt;
    $service = new UserService($repo);&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// 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;br&gt;
it('validates email format', function (string $email, bool $valid) {&lt;br&gt;
    expect(validateEmail($email))-&amp;gt;toBe($valid);&lt;br&gt;
})-&amp;gt;with([&lt;br&gt;
    ['&lt;a href="mailto:valid@email.com"&gt;valid@email.com&lt;/a&gt;', true],&lt;br&gt;
    ['notanemail', false],&lt;br&gt;
    ['', false],&lt;br&gt;
    ['@nodomain.com', false],&lt;br&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="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="gu"&gt;## Unit Test Rules — NON-NEGOTIABLE&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="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="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="gu"&gt;### Coverage target: 80% lines, 75% branches per module&lt;/span&gt;

&lt;span class="gu"&gt;## Project Structure Reference&lt;/span&gt;
src/
  modules/
    users/
      users.service.ts
      users.service.spec.ts   ← unit test lives here
      users.repository.ts
      users.repository.spec.ts
&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;Scope: E2E only — not relevant for unit tests&lt;/li&gt;
&lt;li&gt;Skip for this use case&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;Gives Claude access to project files&lt;/li&gt;
&lt;li&gt;Use in Claude Desktop to read source → generate tests&lt;/li&gt;
&lt;li&gt;Install: configured in &lt;code&gt;claude_desktop_config.json&lt;/code&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;Reads a source file&lt;/li&gt;
&lt;li&gt;Extracts function signatures + types&lt;/li&gt;
&lt;li&gt;Returns structured JSON to Claude&lt;/li&gt;
&lt;li&gt;Claude generates tests from structure, not guesswork
&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="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="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 plaintext"&gt;&lt;code&gt;Generate a unit test file for this [NestJS service / React component / Python class / Angular service / Laravel service].

Rules:
- Library: [Jest / Vitest / pytest / Jest / Pest]
- Test only THIS file — no integration
- Mock ALL dependencies listed in the constructor/props
- Follow AAA pattern with comments
- Minimum 4 test cases per public method
- Use ONLY methods/properties that exist in this source file
- Do NOT import anything not shown in the source
- Naming: "should [behavior] when [condition]"
&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 plaintext"&gt;&lt;code&gt;Read [filename].
Extract:
1. Class/function name
2. All public methods with parameter types and return types
3. All constructor dependencies (for mocking)

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 plaintext"&gt;&lt;code&gt;For each file in [directory], generate a corresponding .spec.ts file.
Process one file at a time.
For each file:
  1. Read the source
  2. List the public methods you found (confirm before generating)
  3. Generate the test file
  4. Show the test file path

Do not proceed to the next file until the current one is confirmed.
&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 plaintext"&gt;&lt;code&gt;src/
  modules/
    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;/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="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>unittests</category>
      <category>testing</category>
      <category>cursor</category>
      <category>pytest</category>
    </item>
    <item>
      <title>My First Automated Post</title>
      <dc:creator>Bhaumik</dc:creator>
      <pubDate>Mon, 22 Jun 2026 13:12:30 +0000</pubDate>
      <link>https://dev.to/bhaumik-viitor/my-first-automated-post-gb3</link>
      <guid>https://dev.to/bhaumik-viitor/my-first-automated-post-gb3</guid>
      <description>&lt;p&gt;This post was published automatically using BlogBot.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why automation matters
&lt;/h2&gt;

&lt;p&gt;Saving time is not just about efficiency — it compounds.&lt;/p&gt;

&lt;h2&gt;
  
  
  How it works
&lt;/h2&gt;

&lt;p&gt;One markdown file. One command. Published.&lt;/p&gt;

</description>
      <category>automation</category>
      <category>python</category>
      <category>playwright</category>
    </item>
    <item>
      <title>My First Automated Post</title>
      <dc:creator>Bhaumik</dc:creator>
      <pubDate>Mon, 22 Jun 2026 05:10:55 +0000</pubDate>
      <link>https://dev.to/bhaumik-viitor/my-first-automated-post-1kpd</link>
      <guid>https://dev.to/bhaumik-viitor/my-first-automated-post-1kpd</guid>
      <description>&lt;p&gt;This post was published automatically using BlogBot.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why automation matters
&lt;/h2&gt;

&lt;p&gt;Saving time is not just about efficiency — it compounds.&lt;/p&gt;

&lt;h2&gt;
  
  
  How it works
&lt;/h2&gt;

&lt;p&gt;One markdown file. One command. Published.&lt;/p&gt;

</description>
    </item>
  </channel>
</rss>
