بنقرة واحدة
testing-strategies
Use this skill when writing tests, implementing TDD, or setting up test infrastructure.
التثبيت باستخدام Codex أو Claude انسخ هذا Prompt والصقه في Codex أو Claude أو مساعد آخر ليراجع صفحة Skill ويثبّتها لك.
القائمة
Use this skill when writing tests, implementing TDD, or setting up test infrastructure.
التثبيت باستخدام Codex أو Claude انسخ هذا Prompt والصقه في Codex أو Claude أو مساعد آخر ليراجع صفحة Skill ويثبّتها لك.
This skill should be used when the user asks to "run glab commands", "create a GitLab issue", "create a merge request", "check pipeline status", "manage GitLab projects", "create a release", or mentions glab, GitLab CLI, gitlab-cli, merge request, MR, GitLab pipeline, GitLab CI, GitLab issue keys, or gitlab operations via the command line.
Use this skill when the user asks about Conductor concepts, workflow patterns, track lifecycle, plan structures, or context-driven development principles. Also activate when working with conductor/ directory files or when implementing tasks following TDD and verification protocols.
This skill should be used when the user asks to "run acli jira commands", "create a Jira issue", "search Jira issues", "manage Jira projects", "transition Jira status", "check jira issue", "consistent with jira issue", or mentions ACLI, Atlassian CLI, Jira CLI, Jira issue keys (e.g. KAN-1, PROJ-123), or jira workitem/project/board/sprint operations via the command line.
Use this skill when working with Java code, Optional handling, CompletableFuture, records, sealed classes, or virtual threads.
Use this skill when designing or implementing REST APIs, endpoints, routes, or controllers.
Use this skill when working with TypeScript code, type definitions, interfaces, generics, or async patterns.
استنادا إلى تصنيف SOC المهني
| name | testing-strategies |
| description | Use this skill when writing tests, implementing TDD, or setting up test infrastructure. |
| version | 1.0.0 |
Guidance for writing effective, maintainable tests. Covers unit testing patterns, integration testing, mocking strategies, and test organization.
describe('UserService', () => {
describe('createUser', () => {
it('should create user with valid data', async () => {
// Arrange
const userData = { name: 'John', email: 'john@example.com' };
const mockRepo = { save: jest.fn().mockResolvedValue({ id: '1', ...userData }) };
const service = new UserService(mockRepo);
// Act
const result = await service.createUser(userData);
// Assert
expect(result.id).toBe('1');
expect(result.name).toBe('John');
expect(mockRepo.save).toHaveBeenCalledWith(userData);
});
});
});
// Pattern: should [expected behavior] when [condition]
it('should return null when user not found', () => {});
it('should throw ValidationError when email is invalid', () => {});
it('should retry 3 times when connection fails', () => {});
// Or: [condition] => [expected behavior]
it('invalid email => throws ValidationError', () => {});
it('user not found => returns null', () => {});
src/
services/
user.ts
user.test.ts # Co-located unit tests
tests/
integration/
user.integration.ts # Integration tests
e2e/
user-flow.e2e.ts # End-to-end tests
fixtures/
users.ts # Shared test data
helpers/
test-db.ts # Test utilities
// Function to test
function calculateTotal(items: Item[]): number {
return items.reduce((sum, item) => sum + item.price * item.quantity, 0);
}
// Tests
describe('calculateTotal', () => {
it('should return 0 for empty array', () => {
expect(calculateTotal([])).toBe(0);
});
it('should calculate total for single item', () => {
const items = [{ price: 10, quantity: 2 }];
expect(calculateTotal(items)).toBe(20);
});
it('should calculate total for multiple items', () => {
const items = [
{ price: 10, quantity: 2 },
{ price: 5, quantity: 3 }
];
expect(calculateTotal(items)).toBe(35);
});
});
// Class to test
class OrderService {
constructor(
private orderRepo: OrderRepository,
private paymentGateway: PaymentGateway
) {}
async placeOrder(order: Order): Promise<OrderResult> {
const savedOrder = await this.orderRepo.save(order);
const payment = await this.paymentGateway.charge(order.total);
return { order: savedOrder, payment };
}
}
// Test with mocks
describe('OrderService', () => {
let service: OrderService;
let mockOrderRepo: jest.Mocked<OrderRepository>;
let mockPaymentGateway: jest.Mocked<PaymentGateway>;
beforeEach(() => {
mockOrderRepo = { save: jest.fn() };
mockPaymentGateway = { charge: jest.fn() };
service = new OrderService(mockOrderRepo, mockPaymentGateway);
});
it('should save order and charge payment', async () => {
// Arrange
const order = { id: '1', total: 100 };
mockOrderRepo.save.mockResolvedValue(order);
mockPaymentGateway.charge.mockResolvedValue({ success: true });
// Act
const result = await service.placeOrder(order);
// Assert
expect(mockOrderRepo.save).toHaveBeenCalledWith(order);
expect(mockPaymentGateway.charge).toHaveBeenCalledWith(100);
expect(result.order).toEqual(order);
});
});
Mock:
Don't Mock:
// Stub - returns canned response
const userRepo = { findById: jest.fn().mockResolvedValue(mockUser) };
// Spy - tracks calls while using real implementation
const spy = jest.spyOn(console, 'log');
// ... run code
expect(spy).toHaveBeenCalledWith('message');
// Fake - simplified working implementation
class FakeUserRepo implements UserRepository {
private users: Map<string, User> = new Map();
async save(user: User) {
this.users.set(user.id, user);
return user;
}
async findById(id: string) {
return this.users.get(id);
}
}
// Mock module
jest.mock('./database', () => ({
query: jest.fn()
}));
// Mock specific method
jest.spyOn(Date, 'now').mockReturnValue(1234567890);
// Mock implementation
mockFn.mockImplementation((x) => x * 2);
// Mock once (for specific test)
mockFn.mockResolvedValueOnce(firstResult);
mockFn.mockResolvedValueOnce(secondResult);
// Reset mocks between tests
beforeEach(() => {
jest.clearAllMocks();
});
describe('UserRepository', () => {
let db: Database;
let repo: UserRepository;
beforeAll(async () => {
db = await createTestDatabase();
});
afterAll(async () => {
await db.close();
});
beforeEach(async () => {
await db.clear();
repo = new UserRepository(db);
});
it('should persist and retrieve user', async () => {
// Arrange
const user = { name: 'John', email: 'john@example.com' };
// Act
const saved = await repo.create(user);
const found = await repo.findById(saved.id);
// Assert
expect(found).toEqual(saved);
});
});
describe('POST /api/users', () => {
let app: Express;
beforeAll(() => {
app = createApp();
});
it('should create user and return 201', async () => {
const response = await request(app)
.post('/api/users')
.send({ name: 'John', email: 'john@example.com' });
expect(response.status).toBe(201);
expect(response.body.data).toHaveProperty('id');
expect(response.body.data.name).toBe('John');
});
it('should return 422 for invalid email', async () => {
const response = await request(app)
.post('/api/users')
.send({ name: 'John', email: 'invalid' });
expect(response.status).toBe(422);
expect(response.body.error.code).toBe('VALIDATION_ERROR');
});
});
| Metric | Target | Critical Path |
|---|---|---|
| Line | 80% | 95%+ |
| Branch | 75% | 90%+ |
| Function | 85% | 95%+ |
// Don't write tests just for coverage
// Bad - tests implementation, not behavior
it('should call validateEmail', () => {
service.createUser({ email: 'test@example.com' });
expect(validateEmail).toHaveBeenCalled();
});
// Good - tests actual behavior
it('should reject invalid email format', () => {
expect(() => service.createUser({ email: 'invalid' }))
.toThrow(ValidationError);
});
// Equality
expect(value).toBe(expected); // Strict equality
expect(value).toEqual(expected); // Deep equality
expect(value).toBeNull();
expect(value).toBeDefined();
// Truthiness
expect(value).toBeTruthy();
expect(value).toBeFalsy();
// Numbers
expect(value).toBeGreaterThan(3);
expect(value).toBeLessThanOrEqual(10);
expect(value).toBeCloseTo(0.3, 5); // Floating point
// Strings
expect(str).toMatch(/pattern/);
expect(str).toContain('substring');
// Arrays
expect(array).toContain(item);
expect(array).toHaveLength(3);
// Objects
expect(obj).toHaveProperty('key');
expect(obj).toMatchObject({ key: 'value' });
// Exceptions
expect(() => fn()).toThrow();
expect(() => fn()).toThrow(ErrorType);
expect(() => fn()).toThrow('message');
// Async
await expect(promise).resolves.toBe(value);
await expect(promise).rejects.toThrow();