Skills test-generator
git clone https://github.com/TerminalSkills/skills
T=$(mktemp -d) && git clone --depth=1 https://github.com/TerminalSkills/skills "$T" && mkdir -p ~/.claude/skills && cp -r "$T/skills/test-generator" ~/.claude/skills/terminalskills-skills-test-generator && rm -rf "$T"
skills/test-generator/SKILL.mdTest Generator
Overview
Automatically generate comprehensive tests for existing source code. This skill analyzes functions, classes, and modules to produce well-structured test suites with meaningful assertions, edge case coverage, and proper mocking. It supports multiple frameworks and test types (unit, integration, e2e).
Instructions
When a user asks you to generate tests for their code, follow these steps:
Step 1: Analyze the target code
Read the source file(s) and identify:
- Functions/methods to test, their signatures, parameters, and return types
- Dependencies that need mocking (database calls, API requests, file I/O)
- Edge cases — null inputs, empty arrays, boundary values, error paths
- Side effects — state mutations, event emissions, DOM changes
Step 2: Detect the testing framework
Check the project for existing test setup:
# Check package.json for JS/TS projects cat package.json | grep -E "jest|vitest|playwright|cypress|mocha|testing-library" # Check for Python test frameworks cat requirements.txt pyproject.toml setup.cfg 2>/dev/null | grep -E "pytest|unittest|hypothesis" # Check for existing test config ls jest.config* vitest.config* pytest.ini conftest.py .pytest.ini setup.cfg 2>/dev/null
If no framework is detected, recommend based on the project:
- React/Next.js: Vitest + React Testing Library
- Node.js/Express: Jest or Vitest
- Python: Pytest
- E2E/browser: Playwright
Step 3: Generate the test file
Create tests following the framework conventions:
Naming: Place test files next to source files or in a
__tests__/tests directory matching the project convention. Use *.test.ts, *.spec.ts, test_*.py, or *_test.py.
Structure each test with:
- Arrange — set up inputs, mocks, and preconditions
- Act — call the function or perform the action
- Assert — verify the output, side effects, or state changes
For each function, generate tests covering:
- Happy path with typical inputs
- Edge cases (empty input, null, zero, max values)
- Error handling (invalid input, thrown exceptions)
- Boundary conditions
Step 4: Set up mocks and fixtures
Mock external dependencies to isolate the unit under test:
JavaScript/TypeScript (Jest/Vitest):
import { describe, it, expect, vi, beforeEach } from 'vitest'; import { processOrder } from './order-service'; import { db } from './database'; import { sendEmail } from './email-service'; vi.mock('./database'); vi.mock('./email-service'); describe('processOrder', () => { beforeEach(() => { vi.clearAllMocks(); }); it('should save the order and send confirmation email', async () => { const mockOrder = { id: 'ord_123', items: [{ sku: 'WIDGET-A', qty: 2 }], total: 49.98 }; vi.mocked(db.orders.create).mockResolvedValue(mockOrder); vi.mocked(sendEmail).mockResolvedValue({ delivered: true }); const result = await processOrder({ items: [{ sku: 'WIDGET-A', qty: 2 }] }); expect(db.orders.create).toHaveBeenCalledOnce(); expect(sendEmail).toHaveBeenCalledWith(expect.objectContaining({ orderId: 'ord_123' })); expect(result.id).toBe('ord_123'); }); });
Python (Pytest):
import pytest from unittest.mock import patch, MagicMock from order_service import process_order @pytest.fixture def mock_db(): with patch('order_service.db') as mock: mock.orders.create.return_value = {"id": "ord_123", "total": 49.98} yield mock def test_process_order_saves_and_sends_email(mock_db): result = process_order(items=[{"sku": "WIDGET-A", "qty": 2}]) mock_db.orders.create.assert_called_once() assert result["id"] == "ord_123" def test_process_order_rejects_empty_items(): with pytest.raises(ValueError, match="at least one item"): process_order(items=[])
Step 5: Add integration and e2e tests if requested
Integration tests — test multiple modules together with real (or test) databases:
- Use test containers or in-memory databases
- Test API routes end-to-end through the HTTP layer
- Verify database state after operations
E2E tests (Playwright):
import { test, expect } from '@playwright/test'; test('user can add item to cart and checkout', async ({ page }) => { await page.goto('/products'); await page.click('[data-testid="product-widget-a"]'); await page.click('button:has-text("Add to Cart")'); await page.goto('/cart'); await expect(page.locator('.cart-item')).toHaveCount(1); await expect(page.locator('.cart-total')).toContainText('$24.99'); await page.click('button:has-text("Checkout")'); await expect(page).toHaveURL(/\/checkout/); });
Step 6: Verify and report coverage
Run the tests and report results:
# JavaScript npx vitest run --coverage # Python pytest --cov=src --cov-report=term-missing
Report: total tests, pass/fail, and coverage percentage. Suggest additional tests if coverage is below 80%.
Examples
Example 1: Generate unit tests for a utility module
User request: "Write tests for src/utils/string-helpers.ts"
Source code analyzed:
export function slugify(text: string): string { return text.toLowerCase().replace(/\s+/g, '-').replace(/[^a-z0-9-]/g, ''); } export function truncate(text: string, maxLength: number): string { if (text.length <= maxLength) return text; return text.slice(0, maxLength - 3) + '...'; }
Generated test file (
src/utils/string-helpers.test.ts):
import { describe, it, expect } from 'vitest'; import { slugify, truncate } from './string-helpers'; describe('slugify', () => { it('converts spaces to hyphens', () => { expect(slugify('Hello World')).toBe('hello-world'); }); it('removes special characters', () => { expect(slugify('Price: $99.99!')).toBe('price-9999'); }); it('handles empty string', () => { expect(slugify('')).toBe(''); }); it('collapses multiple spaces', () => { expect(slugify('too many spaces')).toBe('too-many-spaces'); }); }); describe('truncate', () => { it('returns original if within limit', () => { expect(truncate('short', 10)).toBe('short'); }); it('truncates and adds ellipsis', () => { expect(truncate('This is a very long sentence', 15)).toBe('This is a ve...'); }); it('handles exact length', () => { expect(truncate('exact', 5)).toBe('exact'); }); });
Result: 7 tests generated, all passing. Coverage: 100% for
string-helpers.ts.
Example 2: Generate Pytest tests for a Flask API endpoint
User request: "Add tests for the /api/users endpoint in app.py"
Source code analyzed:
@app.route('/api/users', methods=['POST']) def create_user(): data = request.get_json() if not data.get('email'): return jsonify({"error": "Email is required"}), 400 user = User(email=data['email'], name=data.get('name', '')) db.session.add(user) db.session.commit() return jsonify({"id": user.id, "email": user.email}), 201
Generated test file (
tests/test_users_api.py):
import pytest from app import app, db @pytest.fixture def client(): app.config['TESTING'] = True app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///:memory:' with app.test_client() as client: with app.app_context(): db.create_all() yield client def test_create_user_success(client): response = client.post('/api/users', json={"email": "alice@example.com", "name": "Alice"}) assert response.status_code == 201 data = response.get_json() assert data["email"] == "alice@example.com" assert "id" in data def test_create_user_missing_email(client): response = client.post('/api/users', json={"name": "Bob"}) assert response.status_code == 400 assert "Email is required" in response.get_json()["error"] def test_create_user_empty_body(client): response = client.post('/api/users', json={}) assert response.status_code == 400
Result: 3 tests generated, all passing. Covers success, validation error, and empty input.
Guidelines
- Always match the existing test framework and style in the project. Do not introduce Jest if the project uses Vitest.
- Place test files following the project's existing convention (co-located vs.
directory).tests/ - Use descriptive test names that explain the expected behavior, not the implementation.
- Mock external dependencies (databases, APIs, file system) but avoid over-mocking — test real logic.
- For each function, aim for at least: one happy path, one error case, one edge case.
- Generate
/beforeEach
setup when tests share common fixtures.afterEach - Do not generate snapshot tests unless explicitly requested — they are brittle and rarely useful.
- When generating e2e tests, use stable selectors (
) over CSS classes.data-testid - If the project has no testing setup, install the framework and create the config file before writing tests.
- Report test count and coverage after generation so the user knows the current state.