# Write Tests

> 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".

- Skill: `aakash-dhar/write-tests` (Agent Skill)
- Install (CLI): `npx skillmds@latest add aakash-dhar/write-tests`
- Raw SKILL.md: https://api.skillmd.com/api/skills/aakash-dhar/write-tests/raw
- Safety review: pending
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: Integrations & APIs
- Author: aakash-dhar (https://skillmd.com/u/aakash-dhar)
- Updated: 2026-09-10
- Page: https://skillmd.com/skills/aakash-dhar/write-tests

---


# 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);

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

      it('applies free shipping for orders over 10000 cents ($100)', async () => {
        const input = createValidOrderInput({
          items: [{ productId: 'prod-001', quantity: 1, priceInCents: 15000 }],
        });
        mockOrderRepo.create.mockResolvedValue(createMockOrder({ totalInCents: 15000 }));
        mockPaymentService.authorize.mockResolvedValue({ transactionId: 'txn-001' });

        const result = await orderService.createOrder(input);

        expect(mockOrderRepo.create).toHaveBeenCalledWith(
          expect.objectContaining({ shippingCostInCents: 0 })
        );
      });
    });

    // Error Cases
    describe('error handling', () => {
      it('throws ValidationError when items array is empty', async () => {
        const input = createValidOrderInput({ items: [] });

        await expect(orderService.createOrder(input)).rejects.toThrow('Order must contain at least one item');
      });

      it('throws ValidationError when quantity is zero or negative', async () => {
        const input = createValidOrderInput({
          items: [{ productId: 'prod-001', quantity: 0, priceInCents: 999 }],
        });

        await expect(orderService.createOrder(input)).rejects.toThrow('Quantity must be at least 1');
      });

      it('throws ValidationError when price is negative', async () => {
        const input = createValidOrderInput({
          items: [{ productId: 'prod-001', quantity: 1, priceInCents: -100 }],
        });

        await expect(orderService.createOrder(input)).rejects.toThrow('Price must be a positive number');
      });

      it('does not save order when payment authorization fails', async () => {
        const input = createValidOrderInput();
        mockPaymentService.authorize.mockRejectedValue(new Error('Card declined'));

        await expect(orderService.createOrder(input)).rejects.toThrow('Card declined');
        expect(mockOrderRepo.create).not.toHaveBeenCalled();
      });

      it('rolls back payment when order save fails', async () => {
        const input = createValidOrderInput();
        mockPaymentService.authorize.mockResolvedValue({ transactionId: 'txn-001' });
        mockOrderRepo.create.mockRejectedValue(new Error('Database connection lost'));

        await expect(orderService.createOrder(input)).rejects.toThrow('Database connection lost');
        expect(mockPaymentService.refund).toHaveBeenCalledWith('txn-001');
      });

      it('does not send notification when order creation fails', async () => {
        const input = createValidOrderInput();
        mockPaymentService.authorize.mockRejectedValue(new Error('Payment failed'));

        await expect(orderService.createOrder(input)).rejects.toThrow();
        expect(mockNotificationService.sendOrderConfirmation).not.toHaveBeenCalled();
      });

      it('still completes order when notification fails (non-critical)', async () => {
        const input = createValidOrderInput();
        mockOrderRepo.create.mockResolvedValue(createMockOrder());
        mockPaymentService.authorize.mockResolvedValue({ transactionId: 'txn-001' });
        mockNotificationService.sendOrderConfirmation.mockRejectedValue(new Error('Email service down'));

        // Should not throw — notification failure is non-critical
        const result = await orderService.createOrder(input);
        expect(result.id).toBe('order-xyz-789');
      });
    });
  });

  describe('cancelOrder', () => {
    it('updates order status to cancelled', async () => {
      mockOrderRepo.findById.mockResolvedValue(createMockOrder({ status: 'pending' }));
      mockOrderRepo.update.mockResolvedValue(createMockOrder({ status: 'cancelled' }));

      const result = await orderService.cancelOrder('order-xyz-789', 'user-abc-123');

      expect(result.status).toBe('cancelled');
    });

    it('refunds payment when cancelling a paid order', async () => {
      mockOrderRepo.findById.mockResolvedValue(
        createMockOrder({ status: 'paid', paymentTransactionId: 'txn-001' })
      );
      mockOrderRepo.update.mockResolvedValue(createMockOrder({ status: 'cancelled' }));

      await orderService.cancelOrder('order-xyz-789', 'user-abc-123');

      expect(mockPaymentService.refund).toHaveBeenCalledWith('txn-001');
    });

    it('throws ForbiddenError when user does not own the order', async () => {
      mockOrderRepo.findById.mockResolvedValue(createMockOrder({ userId: 'different-user' }));

      await expect(
        orderService.cancelOrder('order-xyz-789', 'user-abc-123')
      ).rejects.toThrow('You do not have permission to cancel this order');
    });

    it('throws NotFoundError when order does not exist', async () => {
      mockOrderRepo.findById.mockResolvedValue(null);

      await expect(
        orderService.cancelOrder('nonexistent-id', 'user-abc-123')
      ).rejects.toThrow('Order not found');
    });

    it('throws ConflictError when order is already shipped', async () => {
      mockOrderRepo.findById.mockResolvedValue(createMockOrder({ status: 'shipped' }));

      await expect(
        orderService.cancelOrder('order-xyz-789', 'user-abc-123')
      ).rejects.toThrow('Cannot cancel an order that has already been shipped');
    });

    it('throws ConflictError when order is already cancelled', async () => {
      mockOrderRepo.findById.mockResolvedValue(createMockOrder({ status: 'cancelled' }));

      await expect(
        orderService.cancelOrder('order-xyz-789', 'user-abc-123')
      ).rejects.toThrow('Order is already cancelled');
    });
  });
});
```

### TypeScript / JavaScript — Vitest
```typescript
import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest';
import { calculateShipping } from '../services/shipping';
import type { Order, Address } from '../models/order';

describe('calculateShipping', () => {
  const createOrder = (overrides?: Partial<Order>): Order => ({
    id: 'order-001',
    totalWeightGrams: 500,
    totalInCents: 5000,
    items: [{ productId: 'p1', quantity: 1, priceInCents: 5000 }],
    ...overrides,
  });

  const createAddress = (overrides?: Partial<Address>): Address => ({
    country: 'US',
    state: 'CA',
    zip: '90210',
    ...overrides,
  });

  it('calculates domestic standard shipping based on weight', () => {
    const order = createOrder({ totalWeightGrams: 1000 });
    const address = createAddress();

    const cost = calculateShipping(order, address, 'standard');

    expect(cost).toBe(599); // base rate for 1kg domestic
  });

  it('returns zero for orders over $100 (free shipping)', () => {
    const order = createOrder({ totalInCents: 15000 });
    const address = createAddress();

    const cost = calculateShipping(order, address, 'standard');

    expect(cost).toBe(0);
  });

  it('charges higher rate for express shipping', () => {
    const order = createOrder({ totalWeightGrams: 1000 });
    const address = createAddress();

    const standard = calculateShipping(order, address, 'standard');
    const express = calculateShipping(order, address, 'express');

    expect(express).toBeGreaterThan(standard);
  });

  it('charges international rate for non-US addresses', () => {
    const order = createOrder({ totalWeightGrams: 1000 });
    const domestic = createAddress({ country: 'US' });
    const international = createAddress({ country: 'DE' });

    const domesticCost = calculateShipping(order, domestic, 'standard');
    const internationalCost = calculateShipping(order, international, 'standard');

    expect(internationalCost).toBeGreaterThan(domesticCost);
  });

  it('throws InvalidAddressError for unsupported countries', () => {
    const order = createOrder();
    const address = createAddress({ country: 'XX' });

    expect(() => calculateShipping(order, address, 'standard')).toThrow('Unsupported shipping destination');
  });

  it('handles zero-weight orders (digital products)', () => {
    const order = createOrder({ totalWeightGrams: 0 });
    const address = createAddress();

    const cost = calculateShipping(order, address, 'standard');

    expect(cost).toBe(0);
  });
});
```

### React Component — Testing Library
```typescript
import { render, screen, waitFor, within } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import { describe, it, expect, vi, beforeEach } from 'vitest';
import { LoginForm } from '../components/LoginForm';

// Mock the auth service
const mockLogin = vi.fn();
vi.mock('../services/auth', () => ({
  useAuth: () => ({
    login: mockLogin,
    isLoading: false,
    error: null,
  }),
}));

describe('LoginForm', () => {
  const user = userEvent.setup();

  beforeEach(() => {
    vi.clearAllMocks();
  });

  // --- Rendering ---

  it('renders email and password fields', () => {
    render(<LoginForm />);

    expect(screen.getByLabelText(/email/i)).toBeInTheDocument();
    expect(screen.getByLabelText(/password/i)).toBeInTheDocument();
    expect(screen.getByRole('button', { name: /sign in/i })).toBeInTheDocument();
  });

  it('renders forgot password link', () => {
    render(<LoginForm />);

    expect(screen.getByRole('link', { name: /forgot password/i })).toHaveAttribute(
      'href',
      '/forgot-password'
    );
  });

  // --- Form Interaction ---

  it('allows typing in email and password fields', async () => {
    render(<LoginForm />);

    const emailInput = screen.getByLabelText(/email/i);
    const passwordInput = screen.getByLabelText(/password/i);

    await user.type(emailInput, 'alice@example.com');
    await user.type(passwordInput, 'securePass123');

    expect(emailInput).toHaveValue('alice@example.com');
    expect(passwordInput).toHaveValue('securePass123');
  });

  it('submits form with email and password', async () => {
    mockLogin.mockResolvedValue({ success: true });
    render(<LoginForm />);

    await user.type(screen.getByLabelText(/email/i), 'alice@example.com');
    await user.type(screen.getByLabelText(/password/i), 'securePass123');
    await user.click(screen.getByRole('button', { name: /sign in/i }));

    expect(mockLogin).toHaveBeenCalledWith({
      email: 'alice@example.com',
      password: 'securePass123',
    });
  });

  it('submits form on Enter key press', async () => {
    mockLogin.mockResolvedValue({ success: true });
    render(<LoginForm />);

    await user.type(screen.getByLabelText(/email/i), 'alice@example.com');
    await user.type(screen.getByLabelText(/password/i), 'securePass123{enter}');

    expect(mockLogin).toHaveBeenCalled();
  });

  // --- Validation ---

  it('shows error when email is empty on submit', async () => {
    render(<LoginForm />);

    await user.type(screen.getByLabelText(/password/i), 'securePass123');
    await user.click(screen.getByRole('button', { name: /sign in/i }));

    expect(screen.getByText(/email is required/i)).toBeInTheDocument();
    expect(mockLogin).not.toHaveBeenCalled();
  });

  it('shows error when password is empty on submit', async () => {
    render(<LoginForm />);

    await user.type(screen.getByLabelText(/email/i), 'alice@example.com');
    await user.click(screen.getByRole('button', { name: /sign in/i }));

    expect(screen.getByText(/password is required/i)).toBeInTheDocument();
    expect(mockLogin).not.toHaveBeenCalled();
  });

  it('shows error for invalid email format', async () => {
    render(<LoginForm />);

    await user.type(screen.getByLabelText(/email/i), 'not-an-email');
    await user.type(screen.getByLabelText(/password/i), 'securePass123');
    await user.click(screen.getByRole('button', { name: /sign in/i }));

    expect(screen.getByText(/enter a valid email/i)).toBeInTheDocument();
    expect(mockLogin).not.toHaveBeenCalled();
  });

  // --- Loading State ---

  it('disables submit button while loading', async () => {
    mockLogin.mockImplementation(() => new Promise(() => {})); // never resolves
    render(<LoginForm />);

    await user.type(screen.getByLabelText(/email/i), 'alice@example.com');
    await user.type(screen.getByLabelText(/password/i), 'securePass123');
    await user.click(screen.getByRole('button', { name: /sign in/i }));

    await waitFor(() => {
      expect(screen.getByRole('button', { name: /signing in/i })).toBeDisabled();
    });
  });

  it('shows loading spinner during submission', async () => {
    mockLogin.mockImplementation(() => new Promise(() => {}));
    render(<LoginForm />);

    await user.type(screen.getByLabelText(/email/i), 'alice@example.com');
    await user.type(screen.getByLabelText(/password/i), 'securePass123');
    await user.click(screen.getByRole('button', { name: /sign in/i }));

    await waitFor(() => {
      expect(screen.getByTestId('loading-spinner')).toBeInTheDocument();
    });
  });

  // --- Error Handling ---

  it('displays server error message on failed login', async () => {
    mockLogin.mockRejectedValue(new Error('Invalid email or password'));
    render(<LoginForm />);

    await user.type(screen.getByLabelText(/email/i), 'alice@example.com');
    await user.type(screen.getByLabelText(/password/i), 'wrongPassword');
    await user.click(screen.getByRole('button', { name: /sign in/i }));

    await waitFor(() => {
      expect(screen.getByRole('alert')).toHaveTextContent(/invalid email or password/i);
    });
  });

  it('displays generic error on network failure', async () => {
    mockLogin.mockRejectedValue(new Error('Network error'));
    render(<LoginForm />);

    await user.type(screen.getByLabelText(/email/i), 'alice@example.com');
    await user.type(screen.getByLabelText(/password/i), 'securePass123');
    await user.click(screen.getByRole('button', { name: /sign in/i }));

    await waitFor(() => {
      expect(screen.getByRole('alert')).toHaveTextContent(/something went wrong/i);
    });
  });

  it('clears error when user starts typing again', async () => {
    mockLogin.mockRejectedValue(new Error('Invalid email or password'));
    render(<LoginForm />);

    await user.type(screen.getByLabelText(/email/i), 'alice@example.com');
    await user.type(screen.getByLabelText(/password/i), 'wrong');
    await user.click(screen.getByRole('button', { name: /sign in/i }));

    await waitFor(() => {
      expect(screen.getByRole('alert')).toBeInTheDocument();
    });

    // Start typing again — error should clear
    await user.type(screen.getByLabelText(/password/i), 'x');
    expect(screen.queryByRole('alert')).not.toBeInTheDocument();
  });

  // --- Accessibility ---

  it('focuses email field on mount', () => {
    render(<LoginForm />);

    expect(screen.getByLabelText(/email/i)).toHaveFocus();
  });

  it('moves focus to first error field on validation failure', async () => {
    render(<LoginForm />);

    await user.click(screen.getByRole('button', { name: /sign in/i }));

    expect(screen.getByLabelText(/email/i)).toHaveFocus();
  });

  it('password field has type="password"', () => {
    render(<LoginForm />);

    expect(screen.getByLabelText(/password/i)).toHaveAttribute('type', 'password');
  });
});
```

### Python — Pytest
```python
import pytest
from datetime import datetime, timedelta
from unittest.mock import AsyncMock, MagicMock, patch
from decimal import Decimal

from app.services.order_service import OrderService
from app.models.order import Order, OrderStatus, CreateOrderInput, OrderItem
from app.exceptions import ValidationError, NotFoundError, ForbiddenError, ConflictError


# --- Fixtures ---

@pytest.fixture
def mock_order_repo():
    repo = AsyncMock()
    return repo


@pytest.fixture
def mock_payment_service():
    service = AsyncMock()
    return service


@pytest.fixture
def mock_notification_service():
    service = AsyncMock()
    return service


@pytest.fixture
def order_service(mock_order_repo, mock_payment_service, mock_notification_service):
    return OrderService(
        order_repo=mock_order_repo,
        payment_service=mock_payment_service,
        notification_service=mock_notification_service,
    )


@pytest.fixture
def valid_order_input():
    return CreateOrderInput(
        user_id="user-abc-123",
        items=[
            OrderItem(product_id="prod-001", quantity=2, price_in_cents=2999),
            OrderItem(product_id="prod-002", quantity=1, price_in_cents=4999),
        ],
        shipping_address={
            "street": "123 Main St",
            "city": "Springfield",
            "state": "IL",
            "zip": "62701",
            "country": "US",
        },
    )


@pytest.fixture
def mock_order():
    return Order(
        id="order-xyz-789",
        user_id="user-abc-123",
        status=OrderStatus.PENDING,
        total_in_cents=10997,
        items=[],
        created_at=datetime(2026, 1, 15, 10, 0, 0),
        updated_at=datetime(2026, 1, 15, 10, 0, 0),
    )


# --- Create Order Tests ---

class TestCreateOrder:
    """Tests for OrderService.create_order"""

    async def test_creates_order_with_correct_total(
        self, order_service, valid_order_input, mock_order, mock_order_repo, mock_payment_service
    ):
        mock_order_repo.create.return_value = mock_order
        mock_payment_service.authorize.return_value = {"transaction_id": "txn-001"}

        result = await order_service.create_order(valid_order_input)

        assert result.total_in_cents == 10997  # (2999 * 2) + (4999 * 1)

    async def test_authorizes_payment_before_saving(
        self, order_service, valid_order_input, mock_order, mock_order_repo, mock_payment_service
    ):
        call_order = []
        mock_payment_service.authorize.side_effect = lambda *a, **kw: call_order.append("payment")
        mock_order_repo.create.side_effect = lambda *a, **kw: (call_order.append("save"), mock_order)[1]

        await order_service.create_order(valid_order_input)

        assert call_order == ["payment", "save"]

    async def test_sends_confirmation_notification(
        self, order_service, valid_order_input, mock_order, mock_order_repo,
        mock_payment_service, mock_notification_service
    ):
        mock_order_repo.create.return_value = mock_order
        mock_payment_service.authorize.return_value = {"transaction_id": "txn-001"}

        await order_service.create_order(valid_order_input)

        mock_notification_service.send_order_confirmation.assert_called_once()

    # Edge Cases

    async def test_applies_free_shipping_for_orders_over_100_dollars(
        self, order_service, mock_order, mock_order_repo, mock_payment_service
    ):
        input_data = CreateOrderInput(
            user_id="user-abc-123",
            items=[OrderItem(product_id="prod-001", quantity=1, price_in_cents=15000)],
            shipping_address={"country": "US", "zip": "90210"},
        )
        mock_order_repo.create.return_value = mock_order
        mock_payment_service.authorize.return_value = {"transaction_id": "txn-001"}

        await order_service.create_order(input_data)

        create_call_args = mock_order_repo.create.call_args[0][0]
        assert create_call_args.shipping_cost_in_cents == 0

    # Error Cases

    async def test_raises_validation_error_when_items_empty(self, order_service):
        input_data = CreateOrderInput(
            user_id="user-abc-123",
            items=[],
            shipping_address={"country": "US"},
        )

        with pytest.raises(ValidationError, match="at least one item"):
            await order_service.create_order(input_data)

    async def test_raises_validation_error_when_quantity_is_zero(self, order_service):
        input_data = CreateOrderInput(
            user_id="user-abc-123",
            items=[OrderItem(product_id="prod-001", quantity=0, price_in_cents=999)],
            shipping_address={"country": "US"},
        )

        with pytest.raises(ValidationError, match="Quantity must be at least 1"):
            await order_service.create_order(input_data)

    async def test_does_not_save_order_when_payment_fails(
        self, order_service, valid_order_input, mock_order_repo, mock_payment_service
    ):
        mock_payment_service.authorize.side_effect = Exception("Card declined")

        with pytest.raises(Exception, match="Card declined"):
            await order_service.create_order(valid_order_input)

        mock_order_repo.create.assert_not_called()

    async def test_rolls_back_payment_when_save_fails(
        self, order_service, valid_order_input, mock_order_repo, mock_payment_service
    ):
        mock_payment_service.authorize.return_value = {"transaction_id": "txn-001"}
        mock_order_repo.create.side_effect = Exception("Database connection lost")

        with pytest.raises(Exception, match="Database connection lost"):
            await order_service.create_order(valid_order_input)

        mock_payment_service.refund.assert_called_once_with("txn-001")


# --- Cancel Order Tests ---

class TestCancelOrder:
    """Tests for OrderService.cancel_order"""

    async def test_updates_status_to_cancelled(
        self, order_service, mock_order, mock_order_repo
    ):
        mock_order_repo.find_by_id.return_value = mock_order
        cancelled_order = Order(**{**mock_order.__dict__, "status": OrderStatus.CANCELLED})
        mock_order_repo.update.return_value = cancelled_order

        result = await order_service.cancel_order("order-xyz-789", "user-abc-123")

        assert result.status == OrderStatus.CANCELLED

    async def test_raises_not_found_for_nonexistent_order(
        self, order_service, mock_order_repo
    ):
        mock_order_repo.find_by_id.return_value = None

        with pytest.raises(NotFoundError, match="Order not found"):
            await order_service.cancel_order("nonexistent", "user-abc-123")

    async def test_raises_forbidden_when_user_does_not_own_order(
        self, order_service, mock_order, mock_order_repo
    ):
        mock_order.user_id = "different-user"
        mock_order_repo.find_by_id.return_value = mock_order

        with pytest.raises(ForbiddenError):
            await order_service.cancel_order("order-xyz-789", "user-abc-123")

    async def test_raises_conflict_when_order_already_shipped(
        self, order_service, mock_order, mock_order_repo
    ):
        mock_order.status = OrderStatus.SHIPPED
        mock_order_repo.find_by_id.return_value = mock_order

        with pytest.raises(ConflictError, match="already been shipped"):
            await order_service.cancel_order("order-xyz-789", "user-abc-123")

    @pytest.mark.parametrize(
        "invalid_status",
        [OrderStatus.SHIPPED, OrderStatus.DELIVERED, OrderStatus.CANCELLED],
    )
    async def test_raises_conflict_for_non_cancellable_statuses(
        self, order_service, mock_order, mock_order_repo, invalid_status
    ):
        mock_order.status = invalid_status
        mock_order_repo.find_by_id.return_value = mock_order

        with pytest.raises(ConflictError):
            await order_service.cancel_order("order-xyz-789", "user-abc-123")
```

### Go — Standard Testing
```go
package order_test

import (
	"context"
	"errors"
	"testing"

	"github.com/stretchr/testify/assert"
	"github.com/stretchr/testify/mock"
	"github.com/stretchr/testify/require"
	"myapp/internal/order"
)

// --- Mocks ---

type MockOrderRepo struct {
	mock.Mock
}

func (m *MockOrderRepo) Create(ctx context.Context, o *order.Order) (*order.Order, error) {
	args := m.Called(ctx, o)
	if args.Get(0) == nil {
		return nil, args.Error(1)
	}
	return args.Get(0).(*order.Order), args.Error(1)
}

func (m *MockOrderRepo) FindByID(ctx context.Context, id string) (*order.Order, error) {
	args := m.Called(ctx, id)
	if args.Get(0) == nil {
		return nil, args.Error(1)
	}
	return args.Get(0).(*order.Order), args.Error(1)
}

type MockPaymentService struct {
	mock.Mock
}

func (m *MockPaymentService) Authorize(ctx context.Context, amount int, currency string) (string, error) {
	args := m.Called(ctx, amount, currency)
	return args.String(0), args.Error(1)
}

func (m *MockPaymentService) Refund(ctx context.Context, txnID string) error {
	args := m.Called(ctx, txnID)
	return args.Error(0)
}

// --- Helpers ---

func newValidInput() order.CreateInput {
	return order.CreateInput{
		UserID: "user-abc-123",
		Items: []order.ItemInput{
			{ProductID: "prod-001", Quantity: 2, PriceInCents: 2999},
			{ProductID: "prod-002", Quantity: 1, PriceInCents: 4999},
		},
		ShippingCountry: "US",
	}
}

func newMockOrder() *order.Order {
	return &order.Order{
		ID:            "order-xyz-789",
		UserID:        "user-abc-123",
		Status:        order.StatusPending,
		TotalInCents:  10997,
	}
}

// --- Tests ---

func TestCreateOrder(t *testing.T) {
	t.Run("creates order with correct total", func(t *testing.T) {
		t.Parallel()
		repo := new(MockOrderRepo)
		payment := new(MockPaymentService)
		svc := order.NewService(repo, payment)

		payment.On("Authorize", mock.Anything, 10997, "USD").Return("txn-001", nil)
		repo.On("Create", mock.Anything, mock.AnythingOfType("*order.Order")).Return(newMockOrder(), nil)

		result, err := svc.CreateOrder(context.Background(), newValidInput())

		require.NoError(t, err)
		assert.Equal(t, 10997, result.TotalInCents)
		repo.AssertExpectations(t)
		payment.AssertExpectations(t)
	})

	t.Run("returns error when items slice is empty", func(t *testing.T) {
		t.Parallel()
		repo := new(MockOrderRepo)
		payment := new(MockPaymentService)
		svc := order.NewService(repo, payment)

		input := newValidInput()
		input.Items = []order.ItemInput{}

		_, err := svc.CreateOrder(context.Background(), input)

		require.Error(t, err)
		assert.Contains(t, err.Error(), "at least one item")
		repo.AssertNotCalled(t, "Create")
	})

	t.Run("does not save order when payment fails", func(t *testing.T) {
		t.Parallel()
		repo := new(MockOrderRepo)
		payment := new(MockPaymentService)
		svc := order.NewService(repo, payment)

		payment.On("Authorize", mock.Anything, mock.Anything, mock.Anything).
			Return("", errors.New("card declined"))

		_, err := svc.CreateOrder(context.Background(), newValidInput())

		require.Error(t, err)
		assert.Contains(t, err.Error(), "card declined")
		repo.AssertNotCalled(t, "Create")
	})

	t.Run("refunds payment when save fails", func(t *testing.T) {
		t.Parallel()
		repo := new(MockOrderRepo)
		payment := new(MockPaymentService)
		svc := order.NewService(repo, payment)

		payment.On("Authorize", mock.Anything, mock.Anything, mock.Anything).Return("txn-001", nil)
		repo.On("Create", mock.Anything, mock.Anything).Return(nil, errors.New("db error"))
		payment.On("Refund", mock.Anything, "txn-001").Return(nil)

		_, err := svc.CreateOrder(context.Background(), newValidInput())

		require.Error(t, err)
		payment.AssertCalled(t, "Refund", mock.Anything, "txn-001")
	})

	t.Run("applies free shipping for orders over 10000 cents", func(t *testing.T) {
		t.Parallel()
		repo := new(MockOrderRepo)
		payment := new(MockPaymentService)
		svc := order.NewService(repo, payment)

		input := order.CreateInput{
			UserID: "user-abc-123",
			Items: []order.ItemInput{
				{ProductID: "prod-001", Quantity: 1, PriceInCents: 15000},
			},
			ShippingCountry: "US",
		}

		payment.On("Authorize", mock.Anything, mock.Anything, mock.Anything).Return("txn-001", nil)
		repo.On("Create", mock.Anything, mock.MatchedBy(func(o *order.Order) bool {
			return o.ShippingCostInCents == 0
		})).Return(newMockOrder(), nil)

		_, err := svc.CreateOrder(context.Background(), input)

		require.NoError(t, err)
		repo.AssertExpectations(t)
	})
}

func TestCancelOrder(t *testing.T) {
	t.Run("cancels pending order successfully", func(t *testing.T) {
		t.Parallel()
		repo := new(MockOrderRepo)
		payment := new(MockPaymentService)
		svc := order.NewService(repo, payment)

		pending := newMockOrder()
		pending.Status = order.StatusPending
		repo.On("FindByID", mock.Anything, "order-xyz-789").Return(pending, nil)
		repo.On("Update", mock.Anything, mock.Anything).Return(nil)

		err := svc.CancelOrder(context.Background(), "order-xyz-789", "user-abc-123")

		require.NoError(t, err)
	})

	t.Run("returns error when order not found", func(t *testing.T) {
		t.Parallel()
		repo := new(MockOrderRepo)
		payment := new(MockPaymentService)
		svc := order.NewService(repo, payment)

		repo.On("FindByID", mock.Anything, "nonexistent").Return(nil, order.ErrNotFound)

		err := svc.CancelOrder(context.Background(), "nonexistent", "user-abc-123")

		require.ErrorIs(t, err, order.ErrNotFound)
	})

	t.Run("returns error when user does not own order", func(t *testing.T) {
		t.Parallel()
		repo := new(MockOrderRepo)
		payment := new(MockPaymentService)
		svc := order.NewService(repo, payment)

		o := newMockOrder()
		o.UserID = "different-user"
		repo.On("FindByID", mock.Anything, "order-xyz-789").Return(o, nil)

		err := svc.CancelOrder(context.Background(), "order-xyz-789", "user-abc-123")

		require.ErrorIs(t, err, order.ErrForbidden)
	})
}

// --- Table-Driven Tests ---

func TestCalculateTotal(t *testing.T) {
	tests := []struct {
		name     string
		items    []order.ItemInput
		expected int
	}{
		{
			name:     "single item",
			items:    []order.ItemInput{{Quantity: 1, PriceInCents: 999}},
			expected: 999,
		},
		{
			name:     "multiple items",
			items:    []order.ItemInput{{Quantity: 2, PriceInCents: 500}, {Quantity: 1, PriceInCents: 300}},
			expected: 1300,
		},
		{
			name:     "empty items",
			items:    []order.ItemInput{},
			expected: 0,
		},
		{
			name:     "large quantity",
			items:    []order.ItemInput{{Quantity: 99, PriceInCents: 100}},
			expected: 9900,
		},
	}

	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			t.Parallel()
			result := order.CalculateTotal(tt.items)
			assert.Equal(t, tt.expected, result)
		})
	}
}
```

### Ruby — RSpec
```ruby
require 'rails_helper'

RSpec.describe OrderService do
  let(:order_repo) { instance_double(OrderRepository) }
  let(:payment_service) { instance_double(PaymentService) }
  let(:notification_service) { instance_double(NotificationService) }
  let(:service) { described_class.new(order_repo:, payment_service:, notification_service:) }

  let(:valid_input) do
    {
      user_id: "user-abc-123",
      items: [
        { product_id: "prod-001", quantity: 2, price_in_cents: 2999 },
        { product_id: "prod-002", quantity: 1, price_in_cents: 4999 }
      ],
      shipping_address: { country: "US", zip: "90210" }
    }
  end

  let(:mock_order) do
    build(:order,
      id: "order-xyz-789",
      user_id: "user-abc-123",
      status: :pending,
      total_in_cents: 10_997
    )
  end

  describe "#create_order" do
    context "with valid input" do
      before do
        allow(payment_service).to receive(:authorize).and_return("txn-001")
        allow(order_repo).to receive(:create).and_return(mock_order)
        allow(notification_service).to receive(:send_order_confirmation)
      end

      it "creates order with correct total" do
        result = service.create_order(valid_input)

        expect(result.total_in_cents).to eq(10_997)
      end

      it "authorizes payment before saving" do
        service.create_order(valid_input)

        expect(payment_service).to have_received(:authorize).ordered
        expect(order_repo).to have_received(:create).ordered
      end

      it "sends confirmation notification" do
        service.create_order(valid_input)

        expect(notification_service).to have_received(:send_order_confirmation)
          .with(hash_including(order_id: "order-xyz-789"))
      end
    end

    context "with empty items" do
      it "raises ValidationError" do
        input = valid_input.merge(items: [])

        expect { service.create_order(input) }
          .to raise_error(ValidationError, /at least one item/)
      end
    end

    context "when payment fails" do
      before do
        allow(payment_service).to receive(:authorize).and_raise("Card declined")
      end

      it "does not save the order" do
        expect { service.create_order(valid_

…(truncated)
