TDD in Java from Scratch: How Tests Change Code and Save Your Nerves

Online Python Trainer for Beginners

Learn Python easily without overwhelming theory. Solve practical tasks with automatic checking, get hints in Russian, and write code directly in your browser — no installation required.

Start Course

Why TDD is Not About "Writing Tests," But About "Thinking Differently"

\n\n

Imagine you're building a house. You have blueprints, materials, and a crew. But you start laying bricks without checking the foundation. A month later, you find cracks in the walls. Sound familiar? In programming, this is called "we'll fix it later." And "later" usually comes at 3 AM before deployment.

\n\n

Test-Driven Development (TDD) is a technique that turns the process upside down. You don't write code and then tests. You write a test first — and only then the code that passes that test. Sounds crazy? In practice, it saves hours, nerves, and makes your code cleaner than mountain morning air.

\n\n

In this article, we'll break down TDD in Java with concrete examples. No fluff — just code, the Red-Green-Refactor cycle, and real scenarios. Let's go.

\n\n

What is TDD and How the Red-Green-Refactor Cycle Works

\n\n

TDD is based on three simple steps that repeat cyclically:

\n\n
    \n
  • Red — write a test that fails (it must fail).
  • \n
  • Green — write the minimal code to make the test pass.
  • \n
  • Refactor — improve the code without changing its behavior. The tests remain green.
  • \n
\n\n

It may seem like this slows down development. In reality, it speeds it up. You stop wondering, "does this work?" You know: it works, because the test is green.

\n\n

Key Principles of TDD

\n
    \n
  • Don't write a single line of production code without a test.
  • \n
  • The test should be as simple as possible and check exactly one behavior.
  • \n
  • Write just enough code to make the test pass. No "let's add this just in case."
  • \n
\n\n

Now let's move on to Java and JUnit 5 — the most popular framework for unit testing.

\n\n

Project Setup: Maven, JUnit 5, and Structure

\n\n

For the examples, we'll use Maven. Add the dependency to pom.xml:

\n\n
<dependency>\n    <groupId>org.junit.jupiter</groupId>\n    <artifactId>junit-jupiter-api</artifactId>\n    <version>5.10.0</version>\n    <scope>test</scope>\n</dependency>
\n\n

The folder structure is standard for Maven:

\n
src/\n  main/java/com/example/\n  test/java/com/example/
\n\n

All test classes go into src/test/java. The test class name usually matches the tested class name with the Test suffix. For example, Calculator → CalculatorTest.

\n\n

First TDD Cycle: Building a Calculator from Scratch

\n\n

Task: create a method add(int a, int b) that returns the sum. With TDD, we start not with the class, but with the test.

\n\n

Step 1: Red — Write a Test That Will Fail

\n\n
import org.junit.jupiter.api.Test;\nimport static org.junit.jupiter.api.Assertions.*;\n\npublic class CalculatorTest {\n\n    @Test\n    void shouldAddTwoNumbers() {\n        Calculator calc = new Calculator();\n        int result = calc.add(2, 3);\n        assertEquals(5, result);\n    }\n}
\n\n

Try to run it — the compiler complains: the Calculator class doesn't exist. Great, the red light is on.

\n\n

Step 2: Green — Write the Minimal Code

\n\n

Create the Calculator class with a method that simply returns the sum:

\n\n
public class Calculator {\n    public int add(int a, int b) {\n        return a + b;\n    }\n}
\n\n

Run the test — it's green. The minimal possible implementation worked.

\n\n

Step 3: Refactor

\n\n

At this stage, the code is already simple; there's nothing to refactor. But imagine we want to rename the method or add an overflow check. We do that, and the test still passes. If something breaks — the test will fail and immediately point to the problem.

\n\n

Complex

Blogs

Book Recommendations