Claude
Skills
Sign in
Back

write-tests

Included with Lifetime
$97 forever

Generates comprehensive tests for a given file, function, class, or module. Covers unit tests, integration tests, edge cases, error paths, and mocking. Use when the user says "write tests", "add tests", "test this", "create tests for", "generate test cases", "cover this with tests", or "improve test coverage".

Code Review

What this skill does


# Write Tests Skill

When writing tests, follow this structured process. Good tests verify behavior, catch regressions, and serve as living documentation.

## 1. Discovery — Understand What to Test

Before writing any tests, analyze the code:

### Detect Testing Setup
```bash
# Detect framework and config
cat package.json 2>/dev/null | grep -E "jest|vitest|mocha|ava|playwright|cypress|testing-library"
cat jest.config.* vitest.config.* 2>/dev/null | head -30
cat pyproject.toml 2>/dev/null | grep -A 20 "\[tool.pytest"
cat pytest.ini conftest.py 2>/dev/null | head -20
cat .rspec spec/spec_helper.rb 2>/dev/null | head -20
cat phpunit.xml 2>/dev/null | head -20

# Find existing test examples to match patterns
find . -name "*.test.*" -o -name "*.spec.*" -o -name "test_*" -o -name "*_test.*" | head -10

# Read an existing test file to understand conventions
# (pick the most recent or most relevant one)
```

### Analyze the Code Under Test
```bash
# Read the file to understand its exports and dependencies
cat [target-file]

# Find what it imports (these might need mocking)
grep -E "^import|^from|require\(" [target-file]

# Find what exports it provides (these are what we test)
grep -E "^export|module\.exports" [target-file]

# Find related types/interfaces
grep -E "interface |type |class " [target-file]
```

### Identify Test Cases
For each function/method/class, identify:

1. **Happy path** — normal successful operation
2. **Edge cases** — boundary values, empty inputs, limits
3. **Error cases** — invalid inputs, failures, exceptions
4. **Integration points** — database, API, file system calls
5. **State transitions** — before/after state changes
6. **Concurrency** — race conditions, parallel execution
7. **Security** — malicious inputs, injection attempts

## 2. Test Structure Principles

### Arrange-Act-Assert (AAA)
```
// Arrange — set up the test data and conditions
// Act — execute the code under test
// Assert — verify the results
```

### Test Naming
Use descriptive names that explain the scenario:
```
// Pattern: [unit] [scenario] [expected result]

// ✅ GOOD
"createUser returns user with generated UUID when valid email provided"
"createUser throws ValidationError when email is empty string"
"createUser hashes password with bcrypt before saving"

// 🔴 BAD
"createUser works"
"test 1"
"should work correctly"
```

### Test Organization
```
describe('[Module/Class/Function]', () => {
  describe('[method or scenario group]', () => {
    it('[specific behavior]', () => { ... });
  });
});
```

### What Makes a Good Test
- **Independent** — no test depends on another test's state
- **Deterministic** — same result every time (no random, no timing)
- **Fast** — unit tests < 100ms each
- **Readable** — a test is documentation; anyone should understand it
- **Focused** — one assertion concept per test (can have multiple expect statements)
- **Realistic** — test data resembles real data, not `"test"` and `123`

## 3. Stack-Specific Test Generation

### TypeScript / JavaScript — Jest
```typescript
import { describe, it, expect, jest, beforeEach, afterEach } from '@jest/globals';
import { OrderService } from '../services/orderService';
import { OrderRepository } from '../db/repositories/orderRepository';
import { PaymentService } from '../lib/paymentService';
import { NotificationService } from '../lib/notificationService';
import type { CreateOrderInput, Order } from '../models/order';

// Mock dependencies
jest.mock('../db/repositories/orderRepository');
jest.mock('../lib/paymentService');
jest.mock('../lib/notificationService');

describe('OrderService', () => {
  let orderService: OrderService;
  let mockOrderRepo: jest.Mocked<OrderRepository>;
  let mockPaymentService: jest.Mocked<PaymentService>;
  let mockNotificationService: jest.Mocked<NotificationService>;

  // --- Setup & Teardown ---

  beforeEach(() => {
    mockOrderRepo = new OrderRepository() as jest.Mocked<OrderRepository>;
    mockPaymentService = new PaymentService() as jest.Mocked<PaymentService>;
    mockNotificationService = new NotificationService() as jest.Mocked<NotificationService>;
    orderService = new OrderService(mockOrderRepo, mockPaymentService, mockNotificationService);
  });

  afterEach(() => {
    jest.restoreAllMocks();
  });

  // --- Test Data Factories ---

  const createValidOrderInput = (overrides?: Partial<CreateOrderInput>): CreateOrderInput => ({
    userId: 'user-abc-123',
    items: [
      { productId: 'prod-001', quantity: 2, priceInCents: 2999 },
      { productId: 'prod-002', quantity: 1, priceInCents: 4999 },
    ],
    shippingAddress: {
      street: '123 Main St',
      city: 'Springfield',
      state: 'IL',
      zip: '62701',
      country: 'US',
    },
    ...overrides,
  });

  const createMockOrder = (overrides?: Partial<Order>): Order => ({
    id: 'order-xyz-789',
    userId: 'user-abc-123',
    status: 'pending',
    totalInCents: 10997,
    items: [],
    createdAt: new Date('2026-01-15T10:00:00Z'),
    updatedAt: new Date('2026-01-15T10:00:00Z'),
    ...overrides,
  });

  // --- Tests ---

  describe('createOrder', () => {
    // Happy Path
    describe('when given valid input', () => {
      it('creates an order with correct total calculated from items', async () => {
        const input = createValidOrderInput();
        mockOrderRepo.create.mockResolvedValue(createMockOrder({ totalInCents: 10997 }));
        mockPaymentService.authorize.mockResolvedValue({ transactionId: 'txn-001' });

        const result = await orderService.createOrder(input);

        expect(mockOrderRepo.create).toHaveBeenCalledWith(
          expect.objectContaining({
            userId: 'user-abc-123',
            totalInCents: 10997, // (2999 * 2) + (4999 * 1)
          })
        );
        expect(result.totalInCents).toBe(10997);
      });

      it('authorizes payment before saving the order', async () => {
        const input = createValidOrderInput();
        mockOrderRepo.create.mockResolvedValue(createMockOrder());
        mockPaymentService.authorize.mockResolvedValue({ transactionId: 'txn-001' });

        await orderService.createOrder(input);

        // Verify payment authorization was called before order creation
        const paymentCallOrder = mockPaymentService.authorize.mock.invocationCallOrder[0];
        const repoCallOrder = mockOrderRepo.create.mock.invocationCallOrder[0];
        expect(paymentCallOrder).toBeLessThan(repoCallOrder);
      });

      it('sends order confirmation notification', async () => {
        const input = createValidOrderInput();
        mockOrderRepo.create.mockResolvedValue(createMockOrder());
        mockPaymentService.authorize.mockResolvedValue({ transactionId: 'txn-001' });

        await orderService.createOrder(input);

        expect(mockNotificationService.sendOrderConfirmation).toHaveBeenCalledWith(
          expect.objectContaining({
            userId: 'user-abc-123',
            orderId: 'order-xyz-789',
          })
        );
      });
    });

    // Edge Cases
    describe('edge cases', () => {
      it('handles single item order', async () => {
        const input = createValidOrderInput({
          items: [{ productId: 'prod-001', quantity: 1, priceInCents: 999 }],
        });
        mockOrderRepo.create.mockResolvedValue(createMockOrder({ totalInCents: 999 }));
        mockPaymentService.authorize.mockResolvedValue({ transactionId: 'txn-001' });

        const result = await orderService.createOrder(input);

        expect(result.totalInCents).toBe(999);
      });

      it('handles maximum quantity per item', async () => {
        const input = createValidOrderInput({
          items: [{ productId: 'prod-001', quantity: 99, priceInCents: 100 }],
        });
        mockOrderRepo.create.mockResolvedValue(createMockOrder({ totalInCents: 9900 }));
        mockPaymentService.authorize.mockResolvedValue({ transactionId: 'txn-001' });

        const result = await orderService.createOrder(input);

     

Related in Code Review