NashTech Blog

Classic TDD Vs London TDD Vs BDD When To Use Each

Table of Contents
Classic TDD Vs London TDD Vs BDD When To Use Each

Classic TDD Vs London TDD Vs BDD When To Use Each

1. Why this topic matters

Many teams argue about Classic TDD vs London TDD vs BDD as if only one approach is correct.

In reality:

  • They solve different problems
  • They optimize for different feedback loops
  • Mature teams use all three, intentionally

This article explains what each style is, what problem it fits, and how to choose without confusion.

2. Classic TDD

What it is

Classic TDD (also called Detroit School) focuses on:

  • Testing real behavior
  • Using real collaborators where possible
  • Avoiding mocks unless absolutely necessary

You write tests in the familiar cycle:

Red → Green → Refactor

Characteristics

  • Few mocks
  • More integration-like unit tests
  • Tests verify outputs and state, not interactions

Example (.NET)

[Fact]
public void Calculate_ReturnsSumOfAllOrderItems()
{
var order = new Order(new[]
{
new OrderItem(10, 2),
new OrderItem(5, 1)
});
var calculator = new OrderTotalCalculator();
var total = calculator.Calculate(order);
total.Should().Be(25);
}

When Classic TDD is the right choice

  • Pure business logic
  • Domain models
  • Algorithms and calculations
  • Code with few or no dependencies

3. London TDD (Mockist TDD)

What it is

London TDD focuses on:

  • Interactions between objects
  • Heavy use of mocks and stubs
  • Designing systems as collaborating roles

Instead of checking state, you verify who talks to whom.

Characteristics

  • Mock most dependencies
  • Tests describe orchestration
  • Very fast feedback
  • Strong influence on design

Example (.NET)

public class PaymentProcessor
{
private readonly IBankGateway _bankGateway;
public PaymentProcessor(IBankGateway bankGateway)
{
_bankGateway = bankGateway;
}
public async Task ProcessAsync(Payment payment)
{
await _bankGateway.ChargeAsync(payment.Amount);
}
}
[Fact]
public async Task Should_Charge_BankGateway_When_ProcessingPayment()
{
var bankGateway = new Mock<IBankGateway>();
var processor = new PaymentProcessor(bankGateway.Object);
await processor.ProcessAsync(new Payment(100));
bankGateway.Verify(x => x.ChargeAsync(100), Times.Once);
}

When London TDD is the right choice

  • Application services
  • Use cases
  • Workflow orchestration
  • Code with many dependencies
  • Feature-flag-driven logic

4. BDD (Behavior-Driven Development)

What it is

BDD is not a replacement for TDD.

It is a way to:

  • Describe behavior in business language
  • Align developers, QA, and stakeholders
  • Focus on what the system should do, not how

BDD often uses the Given / When / Then format.

Characteristics

  • Scenario-focused
  • Readable by non-developers
  • Can be automated or not
  • Works on top of Classic or London TDD

Example (.NET-style BDD test)

[Fact]
public void Given_InsufficientBalance_When_Withdrawing_Then_TransactionIsRejected()
{
var account = new BankAccount(balance: 50);
var result = account.Withdraw(100);
result.Should().Be(TransactionResult.Rejected);
}

When BDD is the right choice

  • Business rules
  • Acceptance criteria
  • Complex domain behavior
  • Communication with non-technical stakeholders

5. Side-by-side comparison

AspectClassic TDDLondon TDDBDD
Main focusState & outputInteractionsBehavior & intent
MocksRareFrequentDepends
Design influenceLow–MediumHighMedium
ReadabilityDeveloper-focusedDeveloper-focusedBusiness-friendly
Typical layerDomainApplication / ServicesDomain & Acceptance

6. When should I use each?

Ask yourself 3 questions

  1. Does this class have many dependencies?
  2. Is the logic mainly orchestration or calculation?
  3. Who needs to read and understand this test?

Decision guide

  • Pure business logic? → Classic TDD
  • Orchestrating many collaborators? → London TDD
  • Business rules / acceptance criteria? → BDD

💡 BDD can sit on top of Classic or London TDD

7. Common mistakes

❌ Mocking everything

Leads to:

  • Brittle tests
  • Over-specified behavior

❌ Using London TDD for pure logic

Mocks add noise when calculations are simple.

❌ Thinking BDD is only about tools

BDD is a mindset, not Cucumber or SpecFlow.

8. A practical team guideline

Most successful teams:

  • Use Classic TDD in the Domain layer
  • Use London TDD in Application / Use Case layer
  • Use BDD for naming, scenarios, and acceptance tests

Example Clean Architecture mapping:

  • Domain => Classic TDD + BDD naming
  • Application => London TDD
  • Infrastructure => Integration tests

9. Final thoughts

Classic TDD, London TDD, and BDD are tools, not religions.

The real skill is knowing:

  • What problem am I solving?
  • Who am I optimizing feedback for?

Choose the style that makes your intent clearest and your system safer to change.

Picture of Qui Nguyen

Qui Nguyen

Leave a Comment

Suggested Article

Discover more from NashTech Blog

Subscribe now to keep reading and get access to the full archive.

Continue reading