Introduction to TDD

Welcome to the first lesson of our course on Test Driven Development (TDD) in C++ using Google Test. TDD is an iterative software development process where tests are written prior to developing the actual functionality. This approach helps developers focus on the requirements first, leading to more reliable and maintainable code.

In this lesson, we'll introduce you to the essential elements of TDD, including the Red-Green-Refactor cycle, which serves as the core structure of this methodology. We'll be utilizing tools specially suited for C++: Google Test, a popular testing framework that is robust and integrates well with C++. These tools are excellent for defining and running tests in C++. Let's start by investigating TDD’s core components with a hands-on example.

Writing the First Test (Red)

The TDD process begins with writing a test that fails, marking the "Red" phase. This step allows you to crystallize what the code should achieve before writing the actual implementation. Let's write a test for a Sum function that should eventually add two numbers.

Create a file named math_test.cpp in the tests directory:

#include "gtest/gtest.h"

class Math {
public:
    int Sum(int a, int b);
};

TEST(MathTest, SumAddsTwoNumbersCorrectly) {
    Math math;
    EXPECT_EQ(5, math.Sum(2, 3));
}

This test script:

  • Uses TEST to denote a single test case.
  • Declares a Math class with a Sum method.
  • Calls the Sum method and checks if the result equals 5.

Attempt to run this test although the Math class and Sum method are not yet implemented. It will result in a compilation error, reflecting the "Red" stage, signaling the requirement for implementation.

Expected output:

undefined reference to `Math::Sum(int, int)`

This is a normal failure, illustrating that our test is effectively identifying unimplemented features.

Making the Test Pass (Green)

Our next objective is to write the simplest code possible to make the test pass — the "Green" step. In TDD, it means implementing minimal functionality to satisfy the test conditions. Let’s define the Sum method in a new file math.cpp under the src directory, and ensure that the corresponding math.hpp header file is also included in the src directory to declare the class and its methods:

#include "math.hpp"

int Math::Sum(int a, int b) {
    return 5;
}
#ifndef MATH_HPP_
#define MATH_HPP_

class Math {
public:
    int Sum(int a, int b); 
};

#endif  // MATH_HPP_

This version seems superficial since it doesn't actually add two numbers, but it highlights the TDD focus on passing the test with minimal implementation. By doing so, we've met the test condition.

Re-running the test will produce the following result:

[==========] Running 1 test from 1 test case.
[----------] Global test environment set-up.
[----------] 1 test from MathTest
[ RUN      ] MathTest.SumAddsTwoNumbersCorrectly
[       OK ] MathTest.SumAddsTwoNumbersCorrectly (0 ms)
[----------] 1 test from MathTest (0 ms total)

[----------] Global test environment tear-down
[==========] 1 test from 1 test case ran. (0 ms total)
[  PASSED  ] 1 test.

Seeing the test pass confirms our code meets the given test scenario. Future test cases will guide us to refine the implementation.

Sign up
Join the 1M+ learners on CodeSignal
Be a part of our community of 1M+ users who develop and demonstrate their skills on CodeSignal