Speck, pronounced as /ˈbeɪ.kən/.
Speck is a small and fast unit testing framework for the C programming
language, that helps you to keep track of your programs integrity throughout
your development. It is provided as a set of just two source files that can be
copied into your project. There is also no need for extra scripts that generate
your test code from a specification. Your specification is the test itself and
it too is written in pure C.
Speck offers three ways to integrate it into your C project. You can set it up
by importing it as a Git submodule or by manual install. The preferred method
presently is using a Git submodule. It makes updating Speck a lot easier in
the long run.
Importing Speck as a Git submodule works like importing every other submodule:
$ git submodule add https://github.com/compiler-dept/speck.git
This creates a folder called speck containing the test framework. Speck is
distributed with a Makefile include speck.mk, that makes it a lot easier to
set it up. speck.mk contains all necessary targets and variables to build
Speck and your test suites.
Create a folder called spec that will hold your test suites:
$ mkdir spec
Everything else you have to do, is including the file speck.mk into your
Makefile:
-include speck/speck.mk
Now, all variables and targets needed for Speck are available in your
Makefile. The only thing that is left to do, is creating a target to run your
test suites. Let's call it test:
test: $(SPECK) $(SUITES)
@$(SPECK)
speck.mk also provides you with some variables you can set in your Makefile
to control what is compiled and linked into your test suites:
SPECK_CFLAGS: AdditionalCFLAGSused for compilation of every test suite (e.g.-Werroror-Iinclude).SPECK_LDFLAGS: AdditionalLDFLAGSused for compilation of every test suite (e.g.-Llibs).SPECK_LIBS: Additional files and libraries for linking with every test suite. This is where you put the code you want to test (e.g.-lpthreador justsrc/file.c).
If you are only using *.c files inside the the SPECK_LIBS variable, you can
create an additional Makefile target:
$(SUITES): $(SPECK_LIBS)
This allows you to recompile all suites automatically if some library source has changed.
If you want to put Speck into a folder other than speck, you can do so. But
you have to set the SPECK_PATH variable in your Makefile to the location,
to ensure that Speck is working as expected.
If you aren't using Git or don't want to use a Git submodule you can follow this
manual setup. In order to update your copy of Speck you have to take care of
that yourself, instead of doing a simple git submodule update.
To get started, you just have to copy the files speck.c and speck.h into the
root folder of your C project. Create a folder called spec that will hold your
test suites:
$ mkdir spec
You will need to add some rules to your Makefile in order to compile speck
and your tests.
The first rule you need to add, is the list of test suites:
SUITES=$(patsubst %.c, %.so, $(wildcard spec/*.c))
This wildcard matches all .c files in your spec folder as a single test
suite.
Every Speck test suite is compiled into a shared object file (.so) and then
loaded and executed by Speck. Every piece of code that needs to be tested has
to be compiled additionally into the test suites. For this to work you need to
add another rule to your Makefile:
spec/%.so: spec/%.c
@$(CC) -g -I. -fPIC -shared -o $@ $<
At the end of the second line you can attach further files (.c, .o, .s) or
libraries (-lx) to pull in all code needed for execution. You can also use all
kinds of CFLAGS and other options you need to compile the test suites.
Of course we need a rule to compile Speck itself:
speck: speck.c
$(CC) -std=c11 -o $@ $< -ldl
Don't worry, we're almost done. However, wouldn't it be nice to be able to call
your tests with make test? Therefore we need a last rule:
test: speck $(SUITES)
@./speck
The rule tells make, that if the target test is executed, Speck and all
test suites have to be compiled and then executes Speck.
For your convenience, all the Makefile additions in one place:
SUITES=$(patsubst %.c, %.so, $(wildcard spec/*.c))
spec/%.so: spec/%.c
@$(CC) -g -I. -fPIC -shared -o $@ $<
speck: speck.c
$(CC) -g -std=c11 -o $@ $< -ldl
test: speck $(SUITES)
@./speck
To start writing tests, you have to know, that you can organize your tests in
test suites. Every suite is represented as a .c file in the spec directory.
Let's create a first test suite to test some arithmetics:
$ touch spec/arithmetics.c
The first thing you need to do is insert the include to the header file
speck.h into the suite.
#include <speck.h>
Because the test suites are plain C, you can include any header you want, to build your tests.
Speck searches for specific test functions that are to be executed later. They
must match the following form:
void spec_<name>(void)
{
// test code
}
The only thing you may change is the <name> tag of the function. Speck will
run all functions defined this way. Let's write a first test for our suite:
void spec_addition(void)
{
int number = 4 + 3;
sp_assert_equal_i(number, 7);
}
As you can see, we wrote some code we want to test (int number = 4 + 3;). We
assume we are testing the + operator for its correctness. To give Speck a
way of determining if everything worked out as expected , you have to use
assertions. There are different types of assertions implemented. Scroll down to
find out what assertions are possible. In the addition example above, we let
Speck check that number is indeed 7 at the end of the test.
There are currently the following assertions implemented:
sp_assert(expression): Evaluate the expression and fail if the result is false.sp_assert_equal_i(number_a, number_b): Evaluate the equality of both numbers and fail if they're different.sp_assert_equal_s(str_a, str_b): Evaluate the equality of both strings usingstrcmpand fail if they're different.
If you have finished writing your test suites, you can run Speck:
$ make test
Running the test suites in normal mode is nice and fast, but sometimes you want
to test something other than simple assertions. In this case it can come to
lower level errors like segmentation faults. These may be hard to detect,
because the whole test runner will crash upon a segfault. With the Forking mode, Speck will start every test inside its own forked process. When a test
provokes a segfault, only its corresponding child process will die. The error
that caused the crash will then be reported back to the test runner and is
displayed to the user. To enable the Forking mode you have to run Speck with
the command line option -f:
$ speck -f
You can also change your Makefile to run your tests in Forking mode whenever
you type make test:
test: $(SPECK) $(SUITES)
@$(SPECK) -f
-f: Enable forking mode.-v: Show version number.
If you want to see Speck in real-life you can checkout our
LibCollect project.