10 KiB
Risk-Based Testing - Practical Examples
This file contains detailed examples of applying Minimum Viable Testing philosophy to real Stories.
Purpose: Learning and reference (not loaded during skill execution).
When to use: Study these examples to understand how to trim test plans from excessive coverage-driven testing to minimal risk-based testing.
Example 1: User Login Story (Minimal Approach)
Acceptance Criteria:
- User can login with valid credentials → JWT token returned
- Invalid credentials rejected → 401 error
- Rate limiting after 5 failed attempts → 429 error
Risk Assessment:
| Scenario | Business Impact | Probability | Priority | Test Type |
|---|---|---|---|---|
| Valid login works | 4 (core flow) | 3 (standard auth) | 12 | E2E (baseline) |
| Invalid credentials rejected | 5 (security) | 3 | 15 | E2E (baseline) |
| Rate limiting works | 5 (security, brute force) | 4 (concurrency) | 20 | SKIP - E2E negative covers auth error |
| SQL injection attempt blocked | 5 (security breach) | 2 (Prisma escapes) | 10 | SKIP - framework behavior |
| JWT token format valid | 4 (breaks API calls) | 2 (library tested) | 8 | SKIP - library behavior |
| Password hashing uses bcrypt | 5 (security) | 1 (copy-paste code) | 5 | SKIP - library behavior |
| Custom password strength rules | 5 (security policy) | 4 (complex regex) | 20 | Unit (OUR logic) |
Test Plan (Minimum Viable Testing):
E2E Tests (2 baseline):
- Positive: User enters valid email/password → 200 OK + JWT token → token works for protected API call
- Negative: User enters invalid password → 401 Unauthorized → clear error message shown
Integration Tests (0):
- None needed - 2 baseline E2E tests cover full stack (endpoint → service → database)
Unit Tests (1 - OUR business logic only):
validatePasswordStrength()- OUR custom regex (12+ chars, special symbols, numbers) with 5 edge cases
Total: 3 tests (within realistic goal 2-7)
What changed from 6 → 3 tests:
- ❌ E2E rate limiting test - REMOVED (Priority 20 but tests Redis library, not OUR logic)
- ❌ Integration SQL injection test - REMOVED (testing Prisma escaping, not OUR code)
- ❌ Integration rate limiter test - REMOVED (testing Redis counter, not OUR code)
Why 3 tests sufficient:
- 2 baseline E2E cover all Acceptance Criteria (valid login + error handling)
- 1 Unit test covers OUR custom password policy (not library behavior)
- Rate limiting, SQL escaping, JWT generation = framework/library behavior (trust the library)
Avoided tests (with rationale):
- ❌ Unit test
hashPassword()- bcrypt library behavior, Priority 5 - ❌ Unit test
generateJWT()- jsonwebtoken library behavior, Priority 8 - ❌ Unit test
validateEmail()format - covered by E2E negative test - ❌ Integration test JWT token decoding - jsonwebtoken library behavior
- ❌ Integration test rate limiting - Redis library behavior
- ❌ Integration test SQL injection - Prisma library behavior
Example 2: Product Search Story (Minimal Approach)
Acceptance Criteria:
- User can search products by name → results displayed
- User can filter by category → filtered results
- Empty search returns all products
Risk Assessment:
| Scenario | Business Impact | Probability | Priority | Test Type |
|---|---|---|---|---|
| Search returns correct results | 4 (core feature) | 3 (SQL query) | 12 | E2E (baseline positive) |
| Invalid search returns empty | 3 (UX feedback) | 3 | 9 | E2E (baseline negative) |
| Category filter works | 3 (partial feature) | 3 | 9 | SKIP - covered by positive E2E |
| Empty search shows all | 2 (minor UX) | 2 | 4 | SKIP - Priority too low |
| Pagination works | 3 (UX issue if breaks) | 4 (off-by-one errors) | 12 | SKIP - UI pagination, not business logic |
| Search handles special chars | 3 (breaks search) | 4 (SQL injection risk) | 12 | SKIP - Prisma/PostgreSQL behavior |
| Results sorted by relevance | 2 (minor UX) | 3 | 6 | SKIP - Priority too low |
| Unicode search | 3 (breaks for non-EN) | 4 | 12 | SKIP - database engine behavior |
Test Plan (Minimum Viable Testing):
E2E Tests (2 baseline):
- Positive: User types "laptop" in search → sees products with "laptop" in name/description
- Negative: User types "nonexistent999" → sees "No results found" message
Integration Tests (0):
- None needed - special character escaping is Prisma/PostgreSQL behavior, not OUR logic
Unit Tests (0):
- No complex business logic - simple database search query
Total: 2 tests (minimum baseline)
What changed from 7 → 2 tests:
- ❌ E2E pagination test - REMOVED (UI pagination library, not OUR business logic)
- ❌ Integration special chars test - REMOVED (Prisma query builder escaping, not OUR code)
- ❌ Integration Unicode test - REMOVED (PostgreSQL LIKE operator, not OUR code)
- ❌ Integration 1000-char string test - REMOVED (input validation middleware, not search logic)
- ❌ Integration 500 error test - REMOVED (error handling middleware, not search logic)
Why 2 tests sufficient:
- 2 baseline E2E cover both Acceptance Criteria (successful search + no results case)
- No complex business logic to isolate - just database query (trust Prisma + PostgreSQL)
- Pagination, special characters, Unicode, error handling = framework/library/database behavior
Avoided tests (with rationale):
- ❌ E2E empty search - Priority 4 (manual testing sufficient)
- ❌ E2E category filter - covered by baseline positive test (can search + filter simultaneously)
- ❌ E2E pagination - testing UI pagination library, not OUR code
- ❌ Unit test
buildSearchQuery()- covered by E2E that executes query - ❌ Unit test sorting - Priority 6 (nice-to-have, not critical)
- ❌ Integration test database
LIKEquery - testing PostgreSQL, not OUR code - ❌ Integration test special character escaping - testing Prisma, not OUR code
Example 3: Payment Processing Story (Minimal Approach)
Acceptance Criteria:
- User can pay with credit card → order confirmed
- Failed payment shows error message
- Payment amount matches cart total
Risk Assessment:
| Scenario | Business Impact | Probability | Priority | Test Type |
|---|---|---|---|---|
| Successful payment flow | 5 (money) | 3 (Stripe API) | 15 | E2E (baseline positive) |
| Failed payment handled | 5 (money) | 4 (network issues) | 20 | E2E (baseline negative) |
| Amount calculation correct | 5 (money) | 4 (complex math) | 20 | Unit (OUR calculation logic) |
| Tax calculation by region | 5 (money) | 5 (complex rules) | 25 | Unit (OUR tax rules) |
| Discount calculation | 5 (money) | 4 (business rules) | 20 | Unit (OUR discount logic) |
| Currency conversion | 5 (money) | 5 (API + math) | 25 | SKIP - E2E covers, no complex OUR logic |
| Refund processing | 5 (money) | 3 | 15 | SKIP - E2E positive covers payment flow |
| Duplicate payment prevented | 5 (money) | 4 (race condition) | 20 | SKIP - Stripe API idempotency, not OUR code |
| Transaction rollback on error | 5 (data corruption) | 4 (distributed transaction) | 20 | SKIP - database transaction manager, not OUR code |
| Stripe API 500 error | 5 (money) | 3 | 15 | SKIP - E2E negative covers error handling |
| Webhook processing | 5 (money) | 3 | 15 | SKIP - Stripe webhook mechanism, not complex OUR logic |
Test Plan (Minimum Viable Testing):
E2E Tests (2 baseline):
- Positive: User adds items to cart → proceeds to checkout → enters valid card → payment succeeds → order created in DB
- Negative: User enters invalid card → Stripe rejects → error message shown → order NOT created
Integration Tests (0):
- None needed - currency conversion uses external API (trust API), transaction rollback is database behavior, Stripe idempotency is Stripe behavior
Unit Tests (3 - OUR complex business logic only):
calculateTotal()- OUR calculation: items total + tax (by region) + shipping - discount → correct amount (5 edge cases)calculateTax()- OUR tax rules: different rates by country/state, special product categories (5 edge cases)applyDiscount()- OUR discount logic: percentage discount, fixed amount discount, minimum order threshold (5 edge cases)
Total: 5 tests (within realistic goal 2-7)
What changed from 13 → 5 tests:
- ❌ E2E refund test - REMOVED (Stripe API refund mechanism, covered by positive E2E)
- ❌ Integration Stripe 500 error test - REMOVED (covered by baseline negative E2E)
- ❌ Integration duplicate payment test - REMOVED (Stripe idempotency keys, not OUR code)
- ❌ Integration currency conversion test - REMOVED (external API behavior, not complex OUR logic)
- ❌ Integration transaction rollback test - REMOVED (database transaction manager, not OUR code)
- ❌ Integration webhook test - REMOVED (Stripe webhook mechanism, not complex OUR logic)
- ❌ Unit test
convertCurrency()- REMOVED (external API call, no complex OUR calculation) - ❌ Unit test shipping calculation - MERGED into
calculateTotal()(part of same calculation)
Why 5 tests sufficient:
- 2 baseline E2E cover all Acceptance Criteria (successful payment + failed payment)
- 3 Unit tests cover OUR complex financial calculations (money = Priority 25)
- Currency conversion, transaction rollback, Stripe idempotency, webhooks = external services/framework behavior (trust them)
Avoided tests (with rationale):
- ❌ Integration test currency conversion - external API behavior, not OUR math
- ❌ Integration test transaction rollback - database transaction manager behavior
- ❌ Integration test Stripe idempotency - Stripe API feature, not OUR code
- ❌ Integration test Stripe 500 error - covered by baseline E2E negative test
- ❌ Integration test webhook - Stripe mechanism, not complex OUR logic
- ❌ E2E refund test - Stripe API refund, not different from payment flow
- ❌ Unit test free shipping threshold - part of
calculateTotal()unit test
Version: 1.0.0 Last Updated: 2025-11-14