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 on Cart)
  • PaymentService– Processes payments (depends on OrderProcessor)

Now suppose you accidentally break the Cartclass. 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 Cartis broken, tests for OrderProcessorand even PaymentServicestart 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 Cartcauses 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. 🎯


SoftwareEngineering #Testing #DotNet #CSharp #CleanCode #TDD