For the things we have to learn before we can do them, we learn by doing them. — Aristotle

O

ver the past few months, I have occupied myself with learning data structures and algorithms for the benefit of my career. With a background in electrical engineering, they weren’t exactly my strengths. Besides, having worked in the software industry for a couple of years now, I have learned a lot by doing stuff.

As an exercise, I decided to develop a F_unctional _T_emplate _Library (Similar to STL) as my next project. This way, I could explore functional programming concepts and ways to write them in C++.

Now, if there is one thing I’ve learned from experience, it is that no matter how small your project, you always test it.

With a quick search on the internet, you’d realize that C++ isn’t short of testing frameworks. Popular frameworks such as GTestCppUnit, or Boost.Test offer rich features and allow you to write fixtures. Some even support mocks in their framework.

For a project like this, such frameworks are an overkill. All I wanted was a basic framework that I can include as a header file and not worry about building a library or linking it with the project.

So, what’s the way forward? Write one yourself!

In this post, I’ll show you how you can write a small, header-only, C++ unit testing framework in under 70 lines of code using just four macros.


Getting Started

When it comes to hiding boilerplate code, macros are your saviors. They make it easy to focus on writing tests by abstracting details about the framework.

We’ll start with an account of the four macros.

  1. BEGIN_TEST constructs a testing environment taking in a suite and a method name as arguments. You can add any prerequisites required to set up test cases here. In our case, it opens a test function and defines a boolean variable to store the result.
  2. END_TEST concludes the testing environment by returning the result of the comparison: either true or false.
  3. EXPECT_EQ compares the expected value with the actual value returned from the function under test.
  4. RUN_TEST calls a test case inside the main. You can add statements to check if the test passed by printing to the console, collect statistics, or even measure run times of your function here.
	#include <iomanip>
	#include <iostream>

	#define BEGIN_TEST(TestSuite, TestName)                                    \
	   bool test__##TestSuite##__##TestName(void)                              \
	{                                                                          \
	      bool isTrue{true};

	#define END_TEST                                                           \
	   return isTrue;                                                          \
	}

	#define EXPECT_EQ(arg1, arg2) isTrue &= (arg1 == arg2);

	#define RUN_TEST(TestSuite, TestName)                                      \
	{                                                                          \
	   bool ret = test__##TestSuite##__##TestName();                           \
	   std::cout << std::left << std::setfill('-')                             \
	   << std::setw(50) << #TestSuite " --> " #TestName " ";                   \
	                                                                           \
	   if(ret)                                                                 \
	   {                                                                       \
	      std::cout << std::setw(10)                                           \
	      << std::left << "\x1b[38;5;40m   OK \x1b[0m" /* colored in Green*/   \
	      << std::endl;                                                        \
	   }                                                                       \
	   else                                                                    \ 
	   {                                                                       \
	      std::cout << std::setw(10)                                           \
	      << std::left << "\x1b[38;5;160m   FAILED \x1b[0m" /* colored in Red*/\
	      << std::endl;                                                        \
	   }                                                                       \
	} /* Coloring valid for *nix systems. */

#testing #cpp11 #unit-testing #cpp #c

How to Write a Minimal Unit Testing Framework in C++
2.60 GEEK