Files
freemo d9e5668cec fix(skills): comprehensive final audit pass for programming-patterns skill
Fixes and improvements from exhaustive audit:

Consistency fixes in SKILL.md:
- 'Pipe & Filter' → 'Pipe and Filter' (one stray '&' found and corrected)
- 'Singleton for factory instance' → clarified to 'register factory as
  singleton-scoped via DI container' (less misleading wording)
- Documentation Format section updated with note that SKILL.md itself is the
  authoritative source for related-pattern combinations

Coverage fix — Related Patterns sections:
- Added '## Related Patterns' to ALL 94 pattern files (was 0/94)
- Each section lists 3–6 related patterns with relationship descriptions
- Covers: why they're related, when to prefer one vs the other,
  and which are often confused

SOLID principles → Creational → Structural → Behavioral → Architectural →
Concurrency → Functional → Resilience → Data Access → Messaging →
Testing → Error Handling → Microservice — all 13 categories covered

Code verification:
- Python: 0 failures (all 85 testable blocks pass)
- Go: 0 failures (all 76 testable blocks pass)
- JavaScript: 0 failures (all 78 testable blocks pass)
- All 239 code blocks verified correct after edits

Final skill state:
- 108 files, 36,524 lines across 13 reference categories
- 94/94 pattern files have Related Patterns sections
- 2,815-line SKILL.md with 67 decision trees, 23 scenarios,
  0 broken references, 0 naming inconsistencies
2026-04-15 13:22:13 -04:00

8.2 KiB

Given-When-Then (BDD Scenario Structure)

Problem

Tests written in pure code can be opaque to non-developers. Product owners, QA engineers, and business analysts struggle to understand what behaviour is being verified. This disconnect leads to specifications that diverge from tests and requirements that go unverified.

Solution

Structure tests using the Given-When-Then format from Behaviour-Driven Development (BDD):

  1. Given — Establish the initial context (preconditions).
  2. When — The action or event occurs.
  3. Then — The expected observable outcome.

This is semantically equivalent to Arrange-Act-Assert but uses language that maps directly to user stories and acceptance criteria.

When to Use

  • Acceptance tests that need to be readable by non-developers.
  • BDD workflows with tools like Behave (Python), Cucumber, or Jest-Cucumber.
  • Documenting expected behaviour as living specifications.
  • When stakeholders participate in defining test scenarios.

When to Avoid

  • Low-level unit tests where AAA is more natural and concise.
  • Performance or load tests where scenario structure adds no value.
  • When the team has no BDD workflow and the overhead isn't justified.

Pseudocode

Scenario: Applying a percentage discount to a cart

  Given a shopping cart with items totalling $100
    And a 20% discount coupon "SAVE20"

  When the customer applies the coupon

  Then the cart total should be $80
    And the applied coupon should be "SAVE20"

Python

"""Given-When-Then BDD scenario structure in Python."""
from dataclasses import dataclass, field


# ── Production code ────────────────────────────────────────────

@dataclass
class CartItem:
    name: str
    price: float

@dataclass
class ShoppingCart:
    items: list[CartItem] = field(default_factory=list)
    applied_coupon: str | None = None
    discount_pct: float = 0.0

    def add(self, name: str, price: float) -> None:
        self.items.append(CartItem(name=name, price=price))

    def apply_coupon(self, code: str, discount_pct: float) -> None:
        if self.applied_coupon:
            raise ValueError("A coupon is already applied")
        self.applied_coupon = code
        self.discount_pct = discount_pct

    @property
    def subtotal(self) -> float:
        return sum(item.price for item in self.items)

    @property
    def total(self) -> float:
        return self.subtotal * (1 - self.discount_pct / 100)


# ── BDD-style tests ───────────────────────────────────────────

def test_apply_percentage_discount():
    print("Scenario: Applying a percentage discount to a cart")

    # Given a shopping cart with items totalling $100
    cart = ShoppingCart()
    cart.add("Widget", 60.0)
    cart.add("Gadget", 40.0)
    print(f"  Given a cart with subtotal ${cart.subtotal:.0f}")

    # And a 20% discount coupon "SAVE20"
    coupon_code = "SAVE20"
    coupon_discount = 20.0
    print(f"  And a {coupon_discount:.0f}% discount coupon \"{coupon_code}\"")

    # When the customer applies the coupon
    cart.apply_coupon(coupon_code, coupon_discount)
    print(f"  When the customer applies the coupon")

    # Then the cart total should be $80
    assert cart.total == 80.0, f"Expected 80, got {cart.total}"
    print(f"  Then the cart total should be ${cart.total:.0f} -> PASS")

    # And the applied coupon should be "SAVE20"
    assert cart.applied_coupon == "SAVE20"
    print(f"  And the applied coupon is \"{cart.applied_coupon}\" -> PASS")


def test_cannot_apply_two_coupons():
    print("\nScenario: Cannot apply two coupons")

    # Given a cart with a coupon already applied
    cart = ShoppingCart()
    cart.add("Item", 50.0)
    cart.apply_coupon("FIRST10", 10.0)
    print(f"  Given a cart with coupon \"FIRST10\" applied")

    # When the customer tries to apply another coupon
    print(f"  When the customer applies another coupon")
    try:
        cart.apply_coupon("SECOND20", 20.0)
        assert False, "Expected ValueError"
    except ValueError as e:
        # Then an error is raised
        assert "already applied" in str(e)
        print(f"  Then an error is raised: \"{e}\" -> PASS")


def test_empty_cart_total_is_zero():
    print("\nScenario: Empty cart has zero total")

    # Given an empty shopping cart
    cart = ShoppingCart()
    print("  Given an empty shopping cart")

    # When we check the total
    total = cart.total
    print("  When we check the total")

    # Then the total is 0
    assert total == 0.0
    print(f"  Then the total is ${total:.0f} -> PASS")


if __name__ == "__main__":
    test_apply_percentage_discount()
    test_cannot_apply_two_coupons()
    test_empty_cart_total_is_zero()
    print("\nAll Given-When-Then scenarios passed.")

JavaScript

// given_when_then.js — BDD scenario structure in JavaScript

// ── Production code ──────────────────────────────────────────

class ShoppingCart {
  constructor() {
    this.items = [];
    this.appliedCoupon = null;
    this.discountPct = 0;
  }

  add(name, price) {
    this.items.push({ name, price });
  }

  applyCoupon(code, discountPct) {
    if (this.appliedCoupon) throw new Error("A coupon is already applied");
    this.appliedCoupon = code;
    this.discountPct = discountPct;
  }

  get subtotal() {
    return this.items.reduce((sum, item) => sum + item.price, 0);
  }

  get total() {
    return this.subtotal * (1 - this.discountPct / 100);
  }
}

// ── BDD-style tests ──────────────────────────────────────────

function testApplyPercentageDiscount() {
  console.log("Scenario: Applying a percentage discount to a cart");

  // Given a shopping cart with items totalling $100
  const cart = new ShoppingCart();
  cart.add("Widget", 60);
  cart.add("Gadget", 40);
  console.log(`  Given a cart with subtotal $${cart.subtotal}`);

  // And a 20% discount coupon "SAVE20"
  const couponCode = "SAVE20";
  const couponDiscount = 20;
  console.log(`  And a ${couponDiscount}% discount coupon "${couponCode}"`);

  // When the customer applies the coupon
  cart.applyCoupon(couponCode, couponDiscount);
  console.log("  When the customer applies the coupon");

  // Then the cart total should be $80
  console.assert(cart.total === 80, `Expected 80, got ${cart.total}`);
  console.log(`  Then the cart total should be $${cart.total} -> PASS`);

  // And the applied coupon should be "SAVE20"
  console.assert(cart.appliedCoupon === "SAVE20");
  console.log(`  And the applied coupon is "${cart.appliedCoupon}" -> PASS`);
}

function testCannotApplyTwoCoupons() {
  console.log("\nScenario: Cannot apply two coupons");

  // Given a cart with a coupon already applied
  const cart = new ShoppingCart();
  cart.add("Item", 50);
  cart.applyCoupon("FIRST10", 10);
  console.log('  Given a cart with coupon "FIRST10" applied');

  // When the customer tries to apply another coupon
  console.log("  When the customer applies another coupon");
  try {
    cart.applyCoupon("SECOND20", 20);
    throw new Error("Expected error");
  } catch (e) {
    // Then an error is raised
    console.assert(e.message.includes("already applied"));
    console.log(`  Then an error is raised: "${e.message}" -> PASS`);
  }
}

function testEmptyCartTotalIsZero() {
  console.log("\nScenario: Empty cart has zero total");

  // Given an empty shopping cart
  const cart = new ShoppingCart();
  console.log("  Given an empty shopping cart");

  // When we check the total
  const total = cart.total;
  console.log("  When we check the total");

  // Then the total is 0
  console.assert(total === 0);
  console.log(`  Then the total is $${total} -> PASS`);
}

testApplyPercentageDiscount();
testCannotApplyTwoCoupons();
testEmptyCartTotalIsZero();
console.log("\nAll Given-When-Then scenarios passed.");
  • Arrange-Act-Assert — AAA is the developer-centric equivalent of Given-When-Then; same structure, different vocabulary.
  • Specification — BDD scenarios can be linked to formal specifications, making acceptance criteria executable.