< Home | GitHub repository | Motivation | Example | Unforeseen consequences

walter

Single header library for writing unit tests in C made with fewer complications by avoiding boilerplate. Comparing to other similar libraries this focus on minimizing tests setup. Steps required to create new unit tests are as follow:

  1. Create test file like example.t.c
  2. Include "walter.h" and your library
  3. Write tests with assertions. No need to define main()
  4. Compile and run with: $ cc -o example.t example.t.c && ./example.t

It's the only testing library that I use. Recently it was extended with assertion macros that run a process with optional mocked standard input and test for expected standard output, standard error and exit code.

Motivation

I wanted to write unit tests for a small project. Up to this point I was doing that with assert.h. But there was no structure to it and each time I had to setup it from scratch. So this time I looked around to see what libraries people use in C. There where few promising projects but every single one required preparations and that was discouraging. I wanted something that would get me to the step of writing test assertions as quickly as possible. But many of the libraries required first defining a function for test, then adding it to list of test, then invoking them in main(). Another problem I had with them was that they worked very hard to produce pretty output. It was pretty to look at and to find your mistake by eyes but this is slow. Just give me the full path to file with line number so I can jump to failed assertion.

After my disappointments with those libraries I thought that maybe it is just not possible to reproduce experience from scripting languages in C. It took me a lot of time but finally I found out about __attribute__ ((constructor)). With this I can execute functions before main() is called. I know it is an extension but it is the only way to make it work. And it does work.

Example

#include "walter.h"

TEST("You shall pass")
{
	char buf[4] = {'0','0','4','5'};
	char *str = "David";
	int bool = 1;

	OK(bool);               /* Is boolean true? */
	ASSERT(bool, "text");   /* OK() with custom message */
	SEQ(str, "David");      /* Are strings equal? */
	EQ(buf, "0045", 4);     /* Are buffers equal? */
	SNEQ(str, "Walter");    /* Are strings not equal? */
	NEQ(buf, "123", 3);     /* Are buffers not equal? */
	END();                  /* Force test to end here */
	ASSERT(0, "Fail");      /* Force fail in this line */
}
TEST("Another test") { /*...*/ }
SKIP("Skip this test") { /*...*/ }
ONLY("Run only this test") { /*...*/ }

/* There is no main() function. */
/* Compile and run: $ cc -o example.t example.t.c && ./example.t */

Unforeseen consequences

Because it's so easy to create new tests I no longer hesitate to add them. Also often when I want to write function just to try something it's faster and easier for me to run it using walter instead of creating small program with main() function.