DEV Community

Cover image for A Simple Unit Test Framework for C
Remo Dentato
Remo Dentato

Posted on • Updated on

A Simple Unit Test Framework for C

tst: A Simple Unit Testing Framework for C

Every developer understands the undeniable importance of unit testing. While crafting a piece of software, it's equally crucial to ensure that it functions as intended. For those working in C, a myriad of testing frameworks abound, but I found them quite complex to use and had to write my own, single header unit testing framework.

You can find the entire project on GitHub.

Why tst?

At first glance, tst might seem like just another testing tool in an ocean of options. However, a closer look reveals its carefully thought out features:

  1. Minimalistic Design: One of tst's standout features is its no-nonsense, clean design. There aren't any complicated configurations to wrestle with or convoluted syntaxes to learn. Everything is straightforward, making it an ideal choice for developers who appreciate simplicity and efficiency.

  2. Flexibility in Grouping and Tagging: With tst, you can effortlessly tag and group tests, allowing for selective test executions. You can select which group of tests to execute via argument on the command line, this becomes an invaluable asset for large projects where running the entire test suite can be time-consuming.

  3. Ease of Integration: Incorporating tst into your project couldn't be simpler. Just create a dedicated test directory, place the tst.h header and you're done. Each test will be a single program designed to check that some aspect of the program is working properly.
    I've added a makefile to simplify the management of test. If you add a file named t_xxx.c in the test directory, it will be assumed to be a test and you can compile it with make t_xxx. With make runtest you will compile and execute all the tests in the directory that follow the naming convention.

  4. Expressive Reporting: The framework produces a clear, concise, and informative reports. Each test outcome is reported, making it easy to pinpoint issues.

Function Highlights

Tst comes packed with intuitive functions:

  • tstrun( ... ): Groups and begins test execution, often used to enclose all tests.

  • tstcase( ... ): Define individual test cases with descriptive titles.

  • tstcheck(int test, ... ): Performs a test check and reports pass/fail status.

  • tstassert(int test, ... ): Similar to tstcheck, but halts the entire test suite upon a failure.

  • tstgroup(int test, ... ): A conditional test group. If the initial test is false, the entire group is skipped.

  • tstclk( ... ): Times and reports how long a block of code takes to execute.

  • tstdata( ... ) and tstnote( ... ): Provide additional data or notes for context within your test report.

  • tsttags( ... ): Specify the tags that are defined for selective disabling/enabling of groups of tests.

  • tstsettags(int argc, char **argv): Enable/Disable the tags according to what specified on the command line. For example, to disable tests that are related to MongoDB or files:

  my_test -UseMongDB -UseFiles
Enter fullscreen mode Exit fullscreen mode
  • tsttag(tag): checks if a group of tests is enabled. For example:
   tstgroup(tsttag(UseMongoDB)) {
      // To be executed if the `UseMongoDB` group is enabled
   }

   tstgroup(!tsttag(UseFiles)) {
      // To be executed if the `UseFiles` group is disabled
   }
Enter fullscreen mode Exit fullscreen mode

A Practical Dive

Let's dive into a practical example:

tstrun() {
  tstcase("Basic Arithmetic Checks") {
    tstcheck(1 + 1 == 2, "Addition seems off!");
    tstcheck(2 * 3 == 6, "Multiplication isn't working as expected");
    tstcheck(2 - 2 == 1, "Subtraction has an issue!");  // This will fail!
  }
}
Enter fullscreen mode Exit fullscreen mode

Upon executing the above, tst produces a clean output like:

FILE ▷ basic_arith.c 
CASE┬── Basic Arithmetic Checks » basic_arith.c:4
PASS│  1 + 1 == 2 » basic_arith.c:5
PASS│  2 * 3 == 6 » basic_arith.c:6
FAIL├┬ 2 - 2 == 1 » basic_arith.c:7
    │╰  Subtraction has an issue!
    ╰── 1 KO | 2 OK | 0 SKIP
RSLT ▷ 1 KO | 2 OK | 0 SKIP
Enter fullscreen mode Exit fullscreen mode

The report is crystal clear in identifying the problem. The failing test is flagged, and its associated message pinpoints the issue, all while indicating the precise file and line number.

Conclusion

Tst goes beyond just being a testing framework; it’s an advocate for efficient and effective software development. It strips away complexities, leaving developers with a pure, straightforward testing experience. Whether you're a seasoned C developer or just beginning your coding journey, tst has something valuable to offer. Dive into it, and you might soon find it becoming an indispensable part of your development process.

Happy testing!

Top comments (0)