Ever had a tiny bug in your C# code crash your entire test suite? 😩 Let’s break down why that happens—and how your testing style (London vs. Classical) changes your debugging experience.
Inspired by “Unit Testing: Principles, Practices, and Patterns” by Vladimir Khorikov, here’s a relatable C# example to highlight the difference!
🛒 The Scenario: A Simple Shopping Cart System
Imagine an e-commerce setup with:
-
Cart
– Manages items, calculates totals -
OrderProcessor
– Handles orders (depends onCart
) -
PaymentService
– Processes payments (depends on OrderProcessor)
Now suppose you accidentally break the Cart
class. How does each testing style react?
1️⃣ London-Style Tests (Isolated with Mocks)
In London-style testing, dependencies are mocked, so only tests for the broken component (Cart
) fail.
// London-style test for OrderProcessor (using Moq)
[Fact]
public void OrderProcessor_CreatesInvoice_ReturnsCorrectTotal()
{
var mockCart = new Mock();
mockCart.Setup(c => c.GetTotal()).Returns(100); // Mocked Cart
var processor = new OrderProcessor(mockCart.Object);
var result = processor.CreateInvoice();
Assert.Equal(100, result); // ✅ Passes—even if the REAL Cart is broken!
}
✅ Pros: Fast, focused tests. Easy to pinpoint failures (e.g., Cart only).
❌ Cons: Can give false confidence—misses integration bugs.
In classical testing, real dependencies are used. So if Cart
is broken, tests for OrderProcessor
and even PaymentService
start failing too.
// Classical test for OrderProcessor
[Fact]
public void OrderProcessor_CreatesInvoice_ReturnsCorrectTotal()
{
var cart = new Cart(); // Real Cart instance
cart.AddItem("Book", 50);
var processor = new OrderProcessor(cart);
var result = processor.CreateInvoice();
Assert.Equal(50, result); // ❌ FAILS if Cart.GetTotal() is broken!
}
✅ Pros: Detects integration issues early.
❌ Cons: One bug can trigger a failure avalanche 🌊
🧠 Why This Matters
London-style tests are precise and fast—but can miss real-world breakages.
Classical tests offer stronger guarantees—but debugging them can feel like “whack-a-mole.” 🔨
📘 Khorikov’s Insight
- Classical tests align better with the Test Pyramid, emphasizing integration and reducing over-reliance on mocks.
- A failure avalanche often points to mission-critical code. If breaking
Cart
causes 50 failures? That’s a signal—it’s important!
✅ Silver Linings
- Run tests frequently: If things break, you’ll know you broke it 😅
- Volume of failure = Importance: Failures are feedback, not frustration
💬 Final Thought
Which testing style do you lean toward?
🔍 *London *– for precision and speed?
🌊 *Classical *– for real-world system feedback?
Let’s discuss below—and if you haven’t read Khorikov’s book yet, seriously, it’s a game-changer. 🎯