A Simple Unit Test Framework for C
Tags: c, unittest, testing
Published: 2023-10-12 19:29:10

# `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](https://github.com/rdentato/tst). 

### **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
```

- **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
   }
```

### **A Practical Dive**

Let's dive into a practical example:

```c
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!
  }
}
```

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
```

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!