Writing Tests

A basic unit test file looks like this:


#include "lily-test.h"

LILY_FILE_BEGIN(example_file)


LILY_TEST("example test 1")
{
	CHECK_EQ(1+1, 2, "%d");
}
#include LILY_PUSH_TEST()


LILY_TEST("example test 2")
{
	CHECK_LT(3.0, 4.0, "%0.2f");
}
#include LILY_PUSH_TEST()


#define LILY_FILE_END
#include LILY_REGISTER_TESTS()
	

This will define a function pointer example_file with signature void () that, when called, will execute the two tests and display to stderr any errors that they generate. While there is more boilerplate than in comparable C++ libraries, this means that lily-test supports test auto-registration. To add a new test, just use the LILY_TEST macro as shown, and then follow the function body with #include LILY_PUSH_TEST() to register it. These macros will only work correctly when used between a LILY_FILE_BEGIN and LILY_FILE_END block, and only when used together; using LILY_TEST without a LILY_PUSH_TEST is probably going to throw up a ton of compile errors.

Using a single file

For very small projects, you may be able to get away with using only a single unit test file. In this case, you should set it up along the following lines:


#define LILY_IMPLEMENTATION
#include "lily-test.h"

/* any includes or code to get your tests working */

LILY_FILE_BEGIN(tests)

/* test definitions... */

#define LILY_FILE_END
#include LILY_REGISTER_TESTS()

int main()
{
	lily_begin();
	tests();
	lily_finish();
	return 0;
}
	
However, in most cases you will want to have multiple test files.

Multiple test files

You will need, in addition to your unit test files, a header file that contains extern declarations of the function pointers defined by your files and a main C source file that contains a main function to run all of the function pointers. A nice way to set this up is to use X-macros, like this:


/* tests.h */

#define TESTS \
	X(suite_1) \
	X(suite_2) \
	X(suite_3) \


#define X(suite) extern void (*suite)();
TESTS
#undef X
	

/* tests_main.c */

#define LILY_IMPLEMENTATION
#include "lily-test.h"

int main()
{
	lily_begin();
	#define X(suite) suite();
	TESTS
	#undef X
	lily_finish();
	return 0;
}
	

This is convenient, because it means that when you add a new test file you need only add a single line to the definition of the TESTS macro in tests.h and all of the other relevant code is added for you automatically.

Note that exactly ONE file should define LILY_IMPLEMENTATION. I find it reasonable to make this the same file with the implementation of main but YMMV.