Challenge 3 — Solution Task: Using the Strategy pattern's ShoppingCart from Chapter 2, write a test that uses createMock() to create a fake DiscountStrategy whose apply() method is programmed (via willReturn) to always return 50, then asserts that ShoppingCart's checkout() correctly returns 50 regardless of the price passed in. Explain in a comment why this test never touches PercentageDiscount or FixedAmountDiscount at all. createMock(DiscountStrategy::class); $mockDiscount->method('apply')->willReturn(50.0); $cart = new ShoppingCart($mockDiscount); $this->assertEquals(50.0, $cart->checkout(999.0)); $this->assertEquals(50.0, $cart->checkout(1.0)); } } // Why this test never touches PercentageDiscount or FixedAmountDiscount // at all: // ShoppingCart's own constructor only requires an object implementing // the DiscountStrategy interface - it has no idea, and no way to know, // whether it received a real PercentageDiscount, a real // FixedAmountDiscount, or this test's own mock object. createMock() // generates a fake object that satisfies the DiscountStrategy // interface's type requirement without needing either real // implementation to exist or be instantiated at all. This test is // therefore verifying ONE specific thing in complete isolation: // "does ShoppingCart->checkout() correctly return whatever its // injected DiscountStrategy's apply() method returns" - a question // that has nothing to do with how any particular discount is actually // calculated. Testing PercentageDiscount's own math (10% off, etc.) // would be a separate, dedicated test entirely. ?> Expected test run output: PHPUnit 10.x . 1 / 1 (100%) OK (1 test, 2 assertions) Notes: - willReturn(50.0) programs the mock to always return exactly 50.0 from apply(), completely regardless of what value is actually passed into it - which is precisely why calling checkout() with two wildly different prices (999.0 and 1.0) both still return 50.0 in this test. - This directly demonstrates the chapter's own central point: code written against an interface (DiscountStrategy) is far easier to mock than code tied directly to a concrete class, since the mock only needs to satisfy the interface's method signature, not replicate any real discount calculation logic. - A separate, dedicated test for PercentageDiscount's own apply() method (verifying the actual percentage math) would still be needed elsewhere - this test's own job is narrowly scoped to ShoppingCart's own behavior alone.