Skip to main content

testing-strategy

Comprehensive testing guidance covering test planning, TDD workflow, testing pyramid, and coverage targets. Ensures confidence through layered testing.

Informations de source

Dépôt
All-The-Vibes/skills-catalog
Dernière activité de la source
10 janvier 2026 à 18:10
Langue détectée de SKILL.md
anglais
Étoiles
4
Forks
1

Options d'installation

Le prompt qui vérifie d'abord la source est sélectionné par défaut. Vous pouvez passer à une commande directe ou télécharger une copie locale.

Vérifiez les fichiers source

Lisez SKILL.md et les fichiers associés affichés par SkillsMP avant de décider de l'installer.

Affichage de SKILL.md

SKILL.md
Instructions source · Aperçu en lecture seule
name
testing-strategy
description
Comprehensive testing guidance covering test planning, TDD workflow, testing pyramid, and coverage targets. Ensures confidence through layered testing.
# Testing Strategy Skill ## Core Principle **Confidence through layered testing.** Tests are not just about catching bugs - they enable confident refactoring, document expected behavior, and provide fast feedback during development. A good testing strategy balances thoroughness with maintainability, using the right test type for each validation need. **Effective testing:** - Catches bugs before production - Enables safe refactoring - Documents system behavior - Provides fast feedback loops - Scales with codebase growth --- ## Testing Pyramid **The testing pyramid guides test distribution across layers:** ``` /\ / \ E2E (10%) /----\ - Full system tests / \ - Slow, brittle, expensive /--------\ - Critical user journeys only / \ /------------\ Integration (20%) / \ - Component interactions /----------------\- Database, API, services \----------------/- Medium speed, moderate cost \--------------/ \------------/ Unit (70%) \----------/ - Individual functions \--------/ - Fast, reliable, cheap \------/ - Maximum coverage here \----/ \__/ ``` ### Unit Tests (70% of tests) **Purpose:** Validate individual functions/methods in isolation **Characteristics:** - Fast (milliseconds per test) - No external dependencies (databases, APIs, file system) - Isolated (each test independent) - Deterministic (same input = same output) **What to test:** - Pure functions (input → output) - Business logic - Edge cases and boundary conditions - Error handling - Data transformations **Example (Python):** ```python def calculate_discount(price: float, discount_percent: float) -> float: """Calculate discounted price.""" if price < 0: raise ValueError("Price cannot be negative") if not 0 <= discount_percent <= 100: raise ValueError("Discount must be between 0 and 100") return round(price * (1 - discount_percent / 100), 2) # Unit tests def test_calculate_discount_normal_case(): assert calculate_discount(100.0, 10.0) == 90.0 def test_calculate_discount_zero_discount(): assert calculate_discount(100.0, 0.0) == 100.0 def test_calculate_discount_full_discount(): assert calculate_discount(100.0, 100.0) == 0.0 def test_calculate_discount_rounding(): assert calculate_discount(99.99, 10.0) == 89.99 def test_calculate_discount_negative_price(): with pytest.raises(ValueError, match="Price cannot be negative"): calculate_discount(-10.0, 10.0) def test_calculate_discount_invalid_percent(): with pytest.raises(ValueError, match="Discount must be between"): calculate_discount(100.0, 150.0) ``` ### Integration Tests (20% of tests) **Purpose:** Validate interactions between components **Characteristics:** - Medium speed (seconds per test) - Real dependencies (test database, external services) - Test realistic scenarios - More complex setup/teardown **What to test:** - Database queries and transactions - API endpoint contracts - Service-to-service communication - Cache interactions - File system operations **Example (JavaScript):** ```javascript describe('User API', () => { let db; beforeEach(async () => { // Setup test database db = await createTestDatabase(); await db.migrate(); }); afterEach(async () => { await db.cleanup(); }); it('creates user and stores in database', async () => { const userData = { name: 'Jane Doe', email: 'jane@example.com', role: 'user' }; const response = await request(app) .post('/api/users') .send(userData) .expect(201); // Verify API response expect(response.body).toMatchObject({ id: expect.any(String), name: 'Jane Doe', email: 'jane@example.com', role: 'user' }); // Verify database state const user = await db.users.findById(response.body.id); expect(user.email).toBe('jane@example.com'); }); it('rejects duplicate email addresses', async () => { await db.users.create({ name: 'John Doe', email: 'jane@example.com' }); const response = await request(app) .post('/api/users') .send({ name: 'Jane Doe', email: 'jane@example.com' }) .expect(409); expect(response.body.error).toMatch(/email already exists/i); }); }); ``` ### End-to-End Tests (10% of tests) **Purpose:** Validate complete user workflows through the system **Characteristics:** - Slow (minutes per test) - Full system (UI, backend, database, external services) - Brittle (breaks with UI changes) - Expensive to maintain **What to test:** - Critical user journeys (signup, checkout, core workflows) - Cross-cutting features (authentication, authorization) - Integration with third-party services - Browser compatibility (if web app) **Example (Playwright):** ```javascript test('user can complete checkout flow', async ({ page }) => { // Login await page.goto('/login'); await page.fill('input[name="email"]', 'test@example.com'); await page.fill('input[name="password"]', 'password123'); await page.click('button[type="submit"]'); // Add item to cart await page.goto('/products'); await page.click('text=Product Name'); await page.click('button:has-text("Add to Cart")'); // Proceed to checkout await page.click('text=Cart'); await page.click('text=Checkout'); // Fill shipping info await page.fill('input[name="address"]', '123 Main St'); await page.fill('input[name="city"]', 'San Francisco'); await page.fill('input[name="zip"]', '94102'); // Fill payment info (test mode) await page.fill('input[name="cardNumber"]', '4242424242424242'); await page.fill('input[name="expiry"]', '12/25'); await page.fill('input[name="cvc"]', '123'); // Submit order await page.click('button:has-text("Place Order")'); // Verify confirmation await expect(page.locator('text=Order Confirmed')).toBeVisible(); await expect(page.locator('text=Order #')).toBeVisible(); }); ``` --- ## Test-Driven Development (TDD) **Red-Green-Refactor workflow:** ### 1. Red (Write Failing Test) Write the test first, before implementation. Test should fail because functionality doesn't exist yet. ```python # test_calculator.py def test_add_two_numbers(): calculator = Calculator() result = calculator.add(2, 3) assert result == 5 # FAILS - Calculator doesn't exist yet ``` ### 2. Green (Make Test Pass) Write minimal code to make the test pass. Don't worry about perfection yet. ```python # calculator.py class Calculator: def add(self, a, b): return a + b # PASSES - Simplest implementation ``` ### 3. Refactor (Improve Code) Clean up code while keeping tests passing. Tests give you confidence to refactor safely. ```python # calculator.py (refactored) class Calculator: """Simple calculator for arithmetic operations.""" def add(self, a: float, b: float) -> float: """Add two numbers and return the result.""" if not isinstance(a, (int, float)) or not isinstance(b, (int, float)): raise TypeError("Arguments must be numbers") return a + b ``` ### TDD Benefits - **Design first:** Writing tests forces you to think about API design - **Documentation:** Tests document expected behavior - **Confidence:** Tests enable safe refactoring - **Coverage:** TDD naturally produces high test coverage - **Bug prevention:** Catch bugs before they're written ### When to Use TDD **Good fit:** - Complex business logic - Bug fixes (write failing test, then fix) - API design (tests define the interface) - Critical functionality (payment processing, security) **Poor fit:** - Spike/exploratory work (unknown requirements) - Trivial code (getters/setters) - UI experimentation (rapid iteration) - Throwaway prototypes --- ## Test Structure (AAA Pattern) **Arrange-Act-Assert pattern for clear, maintainable tests:** ### Arrange (Setup) Prepare test data and system state ### Act (Execute) Run the code being tested ### Assert (Verify) Check the results match expectations **Example:** ```python def test_user_checkout_with_discount(): # Arrange user = User(id=1, membership="premium") cart = ShoppingCart() cart.add_item(Product(id=101, price=100.0)) cart.add_item(Product(id=102, price=50.0)) checkout = CheckoutService(discount_calculator=PremiumDiscount()) # Act total = checkout.calculate_total(user, cart) # Assert assert total == 135.0 # 150 - 10% premium discount ``` ### Test Naming Convention **Format:** `test_[unit]_[scenario]_[expected_result]` **Good names:** ```python test_calculate_discount_with_zero_percent_returns_original_price() test_user_login_with_invalid_password_raises_authentication_error() test_get_user_by_id_when_not_found_returns_none() ``` **Bad names:** ```python test_discount() # What about discount? test_case_1() # What is case 1? test_user() # What about user? ``` --- ## Coverage Targets **Coverage is a metric, not a goal. 100% coverage doesn't mean bug-free code.** ### Recommended Coverage by Component Type | Component Type | Target Coverage | Rationale | |----------------|----------------|-----------| | **Business Logic** | 90-100% | Critical functionality, high bug cost | | **API Endpoints** | 80-90% | Public contracts, integration points | | **Data Models** | 70-80% | Validation and constraints | | **Utilities** | 80-90% | Reused across codebase | | **UI Components** | 60-70% | High churn, manual testing viable | | **Configuration** | 50-60% | Simple, low complexity | ### Coverage Metrics **Line coverage:** Percentage of code lines executed by tests - Easy to measure, but can be gamed - 80% line coverage is reasonable target **Branch coverage:** Percentage of code paths executed - Better than line coverage (catches untested conditions) - 70% branch coverage is good target **Mutation coverage:** Tests that fail when code is mutated - Most rigorous, catches weak assertions - Advanced metric, use for critical code ### What NOT to Test **Avoid testing:** - Third-party library internals (trust the library) - Framework code (already tested) - Trivial getters/setters (no logic to test) - Private implementation details (test public interface) - Generated code (already validated by generator) --- ## Mocking and Fixtures ### When to Mock **Mock external dependencies:** - Database connections - API calls to external services - File system operations - Current time (for time-dependent logic) - Random number generation **Don't mock:** - Your own domain logic (test it directly) - Simple data structures - Pure functions (no side effects to mock)
Voir sur GitHub
Ce SKILL.md est tres volumineux, SkillsMP affiche donc ici seulement la premiere section. Voir sur GitHub