mikejsavage.co.uk • About • Archive • RSS • Thanks for blocking ads! Blocking ads owns: AdGuard for Safari / uBlock Origin for everything else
I wanted a C++ unit testing library that isn't gigantic and impossible to understand, doesn't blow up compile times, doesn't need much boilerplate, doesn't put the testing code miles from the code being tested, and doesn't have its own silly build requirements that make it a huge pain in the ass to use. Unfortunately all the C++ testing libraries are either gigantic awful monoliths (e.g. googletest), or tiny C libraries that are a little too inconvenient to actually use (e.g. minunit).
Ideally it wouldn't give you awful compiler errors when you get it wrong but that's probably impossible.
Behold:
#pragma once
#if defined( UNITTESTS )
#include <stdio.h>
#define CONCAT_HELPER( a, b ) a##b
#define CONCAT( a, b ) CONCAT_HELPER( a, b )
#define COUNTER_NAME( x ) CONCAT( x, __COUNTER__ )
#define AT_STARTUP( code ) \
namespace COUNTER_NAME( StartupCode ) { \
static struct AtStartup { \
AtStartup() { code; } \
} AtStartupInstance; \
}
#define UNITTEST( name, body ) \
namespace { \
AT_STARTUP( \
int passed = 0; \
int failed = 0; \
puts( name ); \
body; \
printf( "%d passed, %d failed\n\n", passed, failed ); \
) \
}
#define TEST( p ) \
if( !( p ) ) { \
failed++; \
puts( " FAIL: " #p ); \
} \
else { \
passed++; \
}
#define private public
#define protected public
#else
#define UNITTEST( name, body )
#define TEST( p )
#endif
It uses the nifty cinit constructor trick to run your tests before main, and you can dump UNITTESTs anywhere you like (at global scope). Example usage:
#include <stdio.h>
#define UNITTESTS // -DUNITTESTS, etc
#include "ggunit.h"
int main() {
printf( "main\n" );
return 0;
}
UNITTEST( "testing some easy stuff", {
TEST( 1 == 1 );
TEST( 1 == 2 );
} );
UNITTEST( "testing some more easy stuff", {
for( size_t i = 0; i <= 10; i++ ) {
TEST( i < 10 );
}
} );
which prints:
testing some easy stuff
FAIL: 1 == 2
1 passed, 1 failed
testing some more easy stuff
FAIL: i < 10
10 passed, 1 failed
hello
It would be great if you could put UNITTESTs in the middle of classes
etc to test private functionality, but you can't and the simplest
workaround is #define private/protected public
. Super cheesy but it
works. It's not perfect but it works. It's ugly. It's not a
Theoretically Awesome Injection Framework Blah Blah. It works and is two
lines, you can't beat it.
2024 update: Carmack approved lol