Test Data & Mock Generation
Test data and mock factories are areas where Copilot shines — they are repetitive, type-driven, and rarely contain complex logic. This step shows how to generate fixtures and stubs responsibly, including the most important guardrail: never letting real-looking sensitive data into your codebase.
When Copilot generates fixtures, what is your first review priority?
There is no single right answer. Use team context and risk level.
Part A — Fixture Factories for the Checkout Pipeline
A factory function creates test objects with sensible defaults that can be overridden per test. Ask Copilot to generate one from your type. Here the factories mirror the checkout domain used throughout this workshop:
- TypeScript / Jest
- Python / pytest
- Java / JUnit 5
Generate TypeScript factory functions for the checkout pipeline types.
#file:src/models/cart.ts
#file:src/models/order.ts
Factories needed:
1. buildCartItem(overrides?) — CartItem with id, productId, name, price, quantity
2. buildOrder(overrides?) — Order with id, userId, items, subtotal, status ('pending'|'confirmed'|'cancelled')
Use obviously fake defaults. Make all fields overridable via a spread parameter.
Generate Python factory functions for checkout pipeline types.
Factories needed:
1. build_cart_item(**overrides) — dict with id, product_id, name, price, quantity
2. build_order(**overrides) — dict with id, user_id, items, subtotal, status
Use obviously fake defaults. Make all fields overridable via keyword arguments.
Generate Java builder/factory methods for checkout pipeline types.
Factories needed:
1. CartItemBuilder — id, productId, name, price, quantity with fluent overrides
2. OrderBuilder — id, userId, items, subtotal, status
Use obvious test defaults. Use a fluent builder pattern.
// tests/factories.ts (Copilot-generated — matches checkout domain)
export const buildCartItem = (overrides: Partial<CartItem> = {}): CartItem => ({
id: 'item-1',
productId: 'prod_1',
name: 'Workshop T-Shirt',
price: 25,
quantity: 1,
...overrides,
});
export const buildOrder = (overrides: Partial<Order> = {}): Order => ({
id: 'order-1',
userId: 'user-test-01',
items: [buildCartItem()],
subtotal: 25,
status: 'pending',
...overrides,
});
// Fetch mock helper — used in StorePage component tests
export function mockFetchOnce(body: unknown, status = 200) {
(global.fetch as jest.Mock).mockResolvedValueOnce({
ok: status < 300,
status,
json: async () => body,
});
}
// Usage examples:
// const shirt = buildCartItem({ quantity: 3 });
// const confirmed = buildOrder({ status: 'confirmed', subtotal: 90 });
// mockFetchOnce({ data: { items: [buildCartItem()] } });
Defaults are obviously fake ("Workshop T-Shirt", "user-test-01") — not real-looking PII
- Spread overrides let each test express only what it cares about
mockFetchOncereturns a proper Response-like object includingok,status, andjson()
Part B — Mock Service Stubs
Ask Copilot to generate a complete mock for a service interface. This is especially useful for dependency-heavy classes:
Generate a Jest mock factory for NotificationService with methods:
sendOrderConfirmation(orderId: string, email: string): Promise<void>
sendShippingUpdate(orderId: string, trackingUrl: string): Promise<void>
All methods should be jest.fn() returning resolved promises.
// tests/mocks/mockNotificationService.ts (Copilot-generated)
import { NotificationService } from '../../src/services/notificationService';
export const createMockNotificationService = (): jest.Mocked<NotificationService> => ({
sendOrderConfirmation: jest.fn().mockResolvedValue(undefined),
sendShippingUpdate: jest.fn().mockResolvedValue(undefined),
});
// Usage:
// const notifService = createMockNotificationService();
// notifService.sendOrderConfirmation.mockRejectedValueOnce(new Error('SMTP failure'));
Part C — Test Data at Scale with Faker
For tests that need many records (pagination, bulk cart operations), ask Copilot to use a fake data library:
Generate a function that creates an array of N fake CartItem objects using @faker-js/faker.
Fields: id (uuid), productId (uuid), name (commerce.productName), price (number 1-500), quantity (integer 1-10).
Keep prices and quantities in realistic ranges for a checkout pipeline.
// tests/factories/bulkCartFactory.ts (Copilot-generated)
import { faker } from '@faker-js/faker';
import { CartItem } from '../../src/models/cart';
export const createCartItems = (count: number): CartItem[] =>
Array.from({ length: count }, () => ({
id: faker.string.uuid(),
productId: faker.string.uuid(),
name: faker.commerce.productName(),
price: faker.number.float({ min: 1, max: 500, fractionDigits: 2 }),
quantity: faker.number.int({ min: 1, max: 10 }),
}));
Security Guardrail — What to Check
| Risk | Example | Safe Alternative |
|---|---|---|
| Hardcoded passwords | password: 'Secret123!' | password: 'test-password-placeholder' |
| Real-looking API keys | apiKey: 'sk-abc123xyz...' | apiKey: 'test-api-key' |
| Real email domains | email: 'alice@company.com' | email: 'alice@example.com' (RFC 2606 reserved) |
| Real-looking PII | ssn: '123-45-6789' | Use faker.string.alphanumeric(9) |
| JWT tokens | Full valid signed JWT in a fixture | Mock the auth middleware; use 'test-token' |
Configure secret scanning to catch AI-generated test data that looks like credentials before it reaches your repo. Copilot sometimes generates syntactically valid tokens as examples.
Step — Run a Test Using the Factory
// tests/unit/calculateDiscount.test.ts — using checkout factories
import { buildCartItem, buildOrder } from '../factories';
it('FLAT5 is applied to a confirmed order above the minimum', () => {
const order = buildOrder({ subtotal: 50, status: 'confirmed' });
const result = calculateDiscount({ subtotal: order.subtotal, code: 'FLAT5' });
expect(result.discountAmount).toBe(5);
expect(result.finalTotal).toBe(45);
});
it('StorePage renders the cart item name after Add', async () => {
mockFetchOnce({ data: { items: [buildCartItem({ name: 'Workshop T-Shirt' })] } });
// ... render StorePage and assert
});
✓ FLAT5 is applied to a confirmed order above the minimum (2 ms)
The buildOrder factory above does not include adiscount field. Ask Copilot to extend the factory, then review the output for the three most common problems: hardcoded IDs, real-looking amounts, and missing override support.
HintPrompt template
Extend the buildOrder factory to include an optional discount field:
{ code: string; discountAmount: number; finalTotal: number }
Make it optional (undefined by default).
Do not use real-looking amounts — keep values obviously fake (e.g. 5, 10, 25).
BonusShared factory index
Create a tests/factories/index.ts that re-exports all factories. Ask Copilot to generate the barrel file once you have two or more factories.
Key Takeaways
- Factories with
Partial<T>overrides eliminate per-test boilerplate - Copilot generates good factory stubs from TypeScript types — always review for PII risk
- Never commit real-looking credentials, tokens, or PII — even in test files
- Use
example.com(RFC 2606 reserved) for fake email domains - Configure gitleaks or truffleHog in your CI pipeline to catch secret leaks