Skip to main content

test-patterns

Applies proven testing patterns — Arrange-Act-Assert (AAA), Given-When-Then, Test Data Builders, Object Mother, parameterized tests, fixtures, spies, and test doubles — to help write maintainable, reliable, and readable test suites. Use when the user asks about writing unit tests, integration tests, or end-to-end tests; structuring test cases or test suites; applying TDD or BDD practices; working with mocks, stubs, spies, or fakes; improving test coverage or reducing flakiness; or needs guidance on test organization, naming conventions, or assertions in frameworks like Jest, Vitest, pytest, or similar.

معلومات المصدر

المستودع
rohitg00/skillkit
آخر نشاط في المصدر
٦ مارس ٢٠٢٦ في ٠٨:٥٣
لغة SKILL.md المكتشفة
الإنجليزية
النجوم
١٬٥٥٤
التفرعات
١٥٤

خيارات التثبيت

يُحدَّد Prompt الذي يراجع المصدر أولًا بشكل افتراضي. يمكنك التبديل إلى أمر مباشر أو تنزيل نسخة محلية.

مراجعة ملفات المصدر

اقرأ SKILL.md وأي ملفات مرافقة يعرضها SkillsMP قبل أن تقرر التثبيت.

عرض SKILL.md

SKILL.md
تعليمات المصدر · معاينة للقراءة فقط
name
test-patterns
description
Applies proven testing patterns — Arrange-Act-Assert (AAA), Given-When-Then, Test Data Builders, Object Mother, parameterized tests, fixtures, spies, and test doubles — to help write maintainable, reliable, and readable test suites. Use when the user asks about writing unit tests, integration tests, or end-to-end tests; structuring test cases or test suites; applying TDD or BDD practices; working with mocks, stubs, spies, or fakes; improving test coverage or reducing flakiness; or needs guidance on test organization, naming conventions, or assertions in frameworks like Jest, Vitest, pytest, or similar.
version
1.0.0
triggers
["test patterns","testing best practices","how to write tests","test structure","arrange act assert"]
tags
["testing","patterns","quality","best-practices"]
difficulty
intermediate
estimatedTime
10
relatedSkills
["testing/red-green-refactor","testing/anti-patterns"]
# Test Patterns You are applying proven testing patterns to write maintainable, reliable tests. These patterns help ensure tests are readable, focused, and trustworthy. ## Pattern Selection Guide Use this to choose the right pattern for your situation: - **Structuring a single test?** → Arrange-Act-Assert (AAA) or Given-When-Then - **Writing behavior/feature specs?** → Given-When-Then (BDD style) - **Repeating test setup data?** → Test Data Builders - **Many variations of complex objects?** → Object Mother - **Testing same logic with many inputs?** → Parameterized Tests - **Shared setup/teardown across tests?** → Test Fixtures - **Verifying a dependency was called?** → Spy - **Replacing an external dependency?** → Test Doubles (Stub / Mock / Fake) --- ## Pattern Combination Workflows Patterns rarely stand alone — here's how to combine them for common scenarios: **Unit tests (isolated logic):** Fixtures for setup → AAA structure → Stubs/Mocks for dependencies → Parameterized Tests for multiple input cases **Integration tests (service + external dependencies):** Fixtures for setup → AAA structure → Fakes for external services (e.g. in-memory DB) → Spies to verify interaction points **BDD / feature specs:** Given-When-Then → Object Mother or Test Data Builders for scenario data → Fakes for infrastructure **High-variation logic (validators, calculators, formatters):** Parameterized Tests → Test Data Builders to construct each case → AAA structure within each case --- ## Core Pattern: Arrange-Act-Assert (AAA) Structure every test with three distinct phases: ``` // Arrange - Set up test data and dependencies const user = createTestUser({ role: 'admin' }); const service = new UserService(mockRepository); // Act - Execute the code under test const result = await service.updateRole(user.id, 'member'); // Assert - Verify the expected outcome expect(result.role).toBe('member'); expect(mockRepository.save).toHaveBeenCalledWith(user); ``` Guidelines: - Keep sections visually separated (blank lines or comments) - Arrange should be minimal - only what's needed for this test - Act should be a single operation - Assert should verify one logical concept ## Pattern: Given-When-Then (BDD Style) For behavior-focused tests: ``` describe('Shopping Cart', () => { describe('when adding an item', () => { it('should increase the item count', () => { // Given const cart = new Cart(); // When cart.add({ id: '1', quantity: 2 }); // Then expect(cart.itemCount).toBe(2); }); }); }); ``` ## Pattern: Test Data Builders Create flexible test data without repetition: ``` // Builder function function createTestOrder(overrides = {}) { return { id: 'order-123', status: 'pending', items: [], total: 0, ...overrides }; } // Usage const completedOrder = createTestOrder({ status: 'completed', total: 99.99 }); const emptyOrder = createTestOrder({ items: [] }); ``` ## Pattern: Object Mother Factory for complex test objects: ``` class TestUserFactory { static admin() { return new User({ role: 'admin', permissions: ALL_PERMISSIONS }); } static guest() { return new User({ role: 'guest', permissions: [] }); } static withSubscription(tier) { return new User({ subscription: { tier, active: true } }); } } ``` ## Pattern: Parameterized Tests Test multiple cases efficiently: ``` describe('isValidEmail', () => { const validCases = [ 'user@example.com', 'user.name@domain.co.uk', 'user+tag@example.org' ]; const invalidCases = [ '', 'not-an-email', '@no-local.com', 'no-domain@' ]; test.each(validCases)('should accept valid email: %s', (email) => { expect(isValidEmail(email)).toBe(true); }); test.each(invalidCases)('should reject invalid email: %s', (email) => { expect(isValidEmail(email)).toBe(false); }); }); ``` ## Pattern: Test Fixtures Reusable test setup: ``` describe('OrderService', () => { let service; let mockPaymentGateway; let mockInventory; beforeEach(() => { mockPaymentGateway = createMockPaymentGateway(); mockInventory = createMockInventory(); service = new OrderService(mockPaymentGateway, mockInventory); }); afterEach(() => { jest.clearAllMocks(); }); }); ``` ## Pattern: Spy on Dependencies Verify interactions without implementation: ``` it('should send notification on order completion', async () => { const notifySpy = jest.spyOn(notificationService, 'send'); await orderService.complete(orderId); expect(notifySpy).toHaveBeenCalledWith({ type: 'order_completed', orderId: orderId }); }); ``` ## Pattern: Test Doubles Choose the right type: | Type | When to Use | |------|-------------| | **Stub** | Need predictable, canned return values | | **Mock** | Need to assert a dependency was called correctly | | **Spy** | Partial mocking — observe calls on a real object | | **Fake** | Need a working lightweight substitute (e.g. in-memory DB) | ## Pattern: Test Isolation Ensure tests don't affect each other: 1. **Fresh instances** - Create new objects in each test 2. **Reset mocks** - Clear mock state between tests 3. **Clean up** - Remove side effects (files, database rows) 4. **No shared mutable state** - Avoid global variables ## Naming Conventions Test names should describe: - What is being tested - Under what conditions - What the expected outcome is Good examples: - `shouldReturnEmptyArrayWhenNoItemsExist` - `throwsErrorWhenUserNotAuthenticated` - `calculatesDiscountForPremiumMembers` ## Test Organization ``` src/ services/ UserService.ts UserService.test.ts # Co-located tests tests/ integration/ api.test.ts # Integration tests e2e/ checkout.spec.ts # End-to-end tests ``` ## Verification Checklist For each test: - [ ] Single responsibility (tests one thing) - [ ] Clear AAA or GWT structure - [ ] Descriptive name - [ ] Fast execution (< 100ms for unit tests) - [ ] Deterministic (no flakiness) - [ ] Independent (runs in any order)
عرض على GitHub