Why "tests first" is not masochism, but a superpower
\n\nImagine: you write code, everything works. You're happy. A month later you return to the project, change one line — and everything breaks. Sound familiar? Welcome to the club of developers who don't write tests. Now imagine another reality: you change the code, run the tests — and within 10 seconds you know nothing is broken. This isn't magic, it's TDD (Test-Driven Development).
\n\nIn this article, we'll break down TDD using C# as an example. No boring theory. Only practice, code, and real-world cases. If you think TDD is for "pure architects" or "enterprise monsters" — you'll be surprised. It's a tool that will save your code and your nerves.
\n\nWhat is TDD and how Red-Green-Refactor works
\n\nTDD is not about testing. It's about design. You don't write tests after the code, but the other way around: first the test, then the minimal code that passes it, and only then refactoring. This cycle is called Red-Green-Refactor:
\n\n- \n
- Red — write a test that is guaranteed to fail (red). \n
- Green — write the minimal code to make the test pass (green). \n
- Refactor — improve the code without changing its behavior. \n
Seems strange? Let's look at an example. Suppose we need a calculator with an addition method. Usually we write the class, then the test. In TDD — it's the opposite.
\n\nStep 1: Red — write a test that will fail
\n\nusing NUnit.Framework;\n\n[TestFixture]\npublic class CalculatorTests\n{\n [Test]\n public void Add_ShouldReturnSumOfTwoNumbers()\n {\n // Arrange\n var calculator = new Calculator();\n \n // Act\n var result = calculator.Add(2, 3);\n \n // Assert\n Assert.AreEqual(5, result);\n }\n}\n\nRun it — the test fails because the Calculator class doesn't exist. Red is normal. Now our task is to make it green.
\n\nStep 2: Green — minimal code to make the test pass
\n\npublic class Calculator\n{\n public int Add(int a, int b)\n {\n return a + b; // Minimal implementation\n }\n}\n\nThe test is green. Hooray. But the code is still ugly. Let's move to step 3.
\n\nStep 3: Refactor — improve without breaking
\n\nAt this stage, we can add checks, exception handling, or change the architecture. The main thing is that the tests must remain green.
\n\npublic class Calculator\n{\n public int Add(int a, int b)\n {\n if (a < 0 || b < 0)\n throw new ArgumentException("Only positive numbers allowed");\n return a + b;\n }\n}\n\nWill the test fail? Yes. That means we need to update the test or change the logic. In TDD, refactoring is always a dialogue with the tests.
\n\nHow to choose a framework for TDD in C#: NUnit vs xUnit
\n\nIn C#, there are three popular frameworks: NUnit, xUnit, and MSTest. We'll look at the first two, as they are the most flexible.
\n\n| Criteria | \nNUnit | \nxUnit | \n
|---|---|---|
| Attributes | \n[Test], [SetUp] | \n[Fact], [Theory] | \n
| Parameterization | \n[TestCase] | \n[InlineData] | \n