TDD in .NET: Practicing with String Calculator

Article Banner
Author(s): Ajay Kumar
Last updated: 04 Oct 2025

Practicing TDD with a simple String Calculator


When learning Test-Driven Development (TDD), it's tempting to jump straight into complex, real-world problems. But like any skill, TDD is best learned through simple, focused exercises that highlight its core principles without the distractions of complex business logic.

The String Calculator kata, introduced by Roy Osherove, is perfect for this. It starts deceptively simple—adding numbers in a string—but gradually introduces complexity that challenges our TDD discipline and design decisions.

📝 The Challenge


Create a calculator that:

  • Takes a string input (e.g., "1,2")
  • Returns the sum of the numbers
  • Handles empty strings (returns 0)
  • Supports multiple numbers
  • Allows newlines between numbers
  • Supports different delimiters

But here's the catch: we'll build this one test at a time, letting our tests guide the implementation. No peeking ahead at future requirements!

🚀 Starting with the Simplest Case


Following TDD means starting with the absolute simplest case. What's simpler than an empty string?

  1. First, the test (Red):

[Fact]
public void Add_EmptyString_ReturnsZero()
{
    var calculator = new StringCalculator();
    var result = calculator.Add("");
    Assert.Equal(0, result);
}
        
Code Sample #1 : Testing the empty string case

💡 TDD Tip: Notice how we're not thinking about delimiters or multiple numbers yet. TDD is about taking the smallest possible step that moves us forward.

  1. The minimal implementation (Green):

public class StringCalculator
{
    public int Add(string numbers)
    {
        return 0;
    }
}
        
Code Sample #2 : Minimal implementation for empty string

Yes, it's that simple! Resist the urge to implement more than the test requires. This is one of the hardest habits to build in TDD—trusting that complexity will emerge naturally from our tests.

🎯 Adding Single Numbers


Now let's handle single numbers. What's our next test?


[Fact]
public void Add_SingleNumber_ReturnsThatNumber()
{
    var calculator = new StringCalculator();
    var result = calculator.Add("1");
    Assert.Equal(1, result);
}
        
Code Sample #3 : Testing single number input

This fails! Time to update our implementation:


public int Add(string numbers)
{
    if (string.IsNullOrEmpty(numbers))
        return 0;
    
    return int.Parse(numbers);
}
        
Code Sample #4 : Handling single numbers

⚠️ Common Gotcha: At this point, many developers would add error handling for invalid inputs. But in TDD, we only add code that's required by a failing test. No test for invalid input? No error handling yet!

🔄 Handling Two Numbers


Now we're ready to tackle two numbers separated by a comma.


[Fact]
public void Add_TwoNumbers_ReturnsSum()
{
    var calculator = new StringCalculator();
    var result = calculator.Add("1,2");
    Assert.Equal(3, result);
}
        
Code Sample #5 : Testing two number addition

This drives us to enhance our implementation:


public int Add(string numbers)
{
    if (string.IsNullOrEmpty(numbers))
        return 0;

    var numberArray = numbers.Split(',');
    return numberArray.Sum(n => int.Parse(n));
}
        
Code Sample #6 : Implementing two number addition

Notice how our implementation naturally evolved to handle multiple numbers, even though we only tested two! This is a common occurrence in TDD—sometimes the simplest implementation that passes our tests is more general than we expected.

🎓 Key Lessons So Far


1. Baby Steps are Powerful

Each step was tiny, but each one moved us forward with confidence. No step felt risky or overwhelming.

2. Tests Drive Design

Notice how our implementation naturally evolved toward a clean, functional style? That's because our tests focused on behavior, not implementation details.

3. Resist Over-Engineering

Several times we could have added "useful" features (error handling, input validation), but TDD kept us focused on delivering only what was needed.

🔜 Next Steps


We've covered the basics, but there's more to explore! In the next part, we'll tackle:

  • Handling newlines between numbers
  • Supporting custom delimiters
  • Dealing with negative numbers
  • Adding upper bounds for numbers

Each of these requirements will push us to refactor our code while maintaining our test coverage. Stay tuned!

💭 Reflection


The String Calculator kata isn't about building a calculator—it's about building the muscle memory of TDD. Each time you practice it, try to notice:

  • How often do you want to write more code than your tests require?
  • How does starting with tests influence your API design?
  • When do you feel the urge to refactor, and why?

These observations will help you apply TDD more effectively in your day-to-day coding.


Have you tried the String Calculator kata? What surprised you about using TDD for this seemingly simple problem? Share your experiences in the comments below!

Copyright © 2025 Dev Codex

An unhandled error has occurred. Reload 🗙