A simple unit test framework for C and ASM in C.
Written in just one small .h! :D
This project aims to keep unit testing simple, so its pretty easy to use.
First, create a test .c
file, for unit testing I don't like to have the test files in a tests/
directory, I prefer to put them next to the respective .c
so I have both files at hand easily.
Usually a name it *_test.c
, so for the foo.c
file I would create foo_test.c
.
First include the library:
#include "miniunit.h"
// ... other includes
Note: don't forget to compile with -I./MINI_UNIT_DIR
Then, add a TEST_MAIN
and make sure you call the END()
macro at the end:
#include "miniunit.h"
// END() will output the result and exit with 0 if successful, or 1 if failure,
// you can take advatage of that if you automate the execution of tests
TEST_MAIN {
END();
}
Now, you can add TEST_CASE
s and ASSERT
s inside them, and call them from TEST_MAIN
using RUN_TEST
:
#include "miniunit.h"
TEST_CASE(foo) {
int bar = 42;
ASSERT(bar == 42, "bar is not 42!");
}
TEST_MAIN {
RUN_TEST(foo);
END();
}
Of course you can scale this all you want, you can call multiple ASSERT
s in one TEST_CASE
, do more TEST_CASE
s, and since this is just C with macros, you can do whatever you want.
Just renember to call the TEST_CASE
s using RUN_TEST
, and to call END()
at the end.
For a complete usage example, you can check my libasm
project here, in which I use mini-unit
to test the functions of the library.
For unit testing I don't like to have the test files in a tests/
folder, I prefer to put them next to the respective .c
so I have both files at hand easily.
If you also like to place your tests with the original file, you can use the provided Makefile
for automating your tests, just clone this project inside your project directory:
git clone --recurse-submodules https://github.com/izenynn/mini-unit.git
And assuming you project structure is as follows:
project/
├── ...
├── include/
├── src/
├── Makefile
└── mini-unit/
├── Makefile
└── ...
add this to your project Makefile:
# define the necessary variables
# mini-unit location :)
TEST_DIR := mini-unit
# your test files
TEST_SRC_FILES := \
ft_strlen_test.c \
ft_strcmp_test.c
# in my case I have them inside a `src/` directory
TEST_SRC := $(addprefix $(SRC_DIR)/, $(TEST_SRC_FILES))
# create a check rule and make sure you are providing the necessary values:
# - `SRC`: your project src files, in my case it would be something
# like `src/ft_strlen.c src/ft_strcmp.c ...`
#
# - `TEST_SRC`: test sources as showed above
#
# - `RELATIVE_PATH`: the relative path to your project from the 'mini-unit'
# directory location.
#
# this is also used to cut it off from test log output
# so instead of `../src/ft_strlen_test.c` it prints the
# rute relative to the project `src/ft_strlen_test.c`
#
# if you add this to your own Makefile make sure it has the
# correct syntax, check the provided Makefile for details
#
# - `INCLUDES`: mini-unit includes your project path with -I./$(RELATIVE_PATH)
# but if you compile your project with -I./<some_path>,
# add those paths here separated with spaces.
check:
$(MAKE) -C $(TEST_DIR) SRC='$(SRC)' TEST_SRC='$(TEST_SRC)' RELATIVE_PATH='..' INCLUDES='include'
# update your clean rule
clean:
$(MAKE) -C $(TEST_DIR) fclean
# ...
To check a working Makefile
, you can check my libasm
project Makefile
here.
And that's all, now run make test
and have fun! :D
If the provided Makefile
is not an option for your project, you would probably want to add some test
rule to your project Makefile
, here is a quick example assuming your test files follow the *_test.c
naming convention:
CC = gcc
CFLAGS = -Wall -Werror -Wextra
SRC = $(wildcard src/*.c)
TEST_SRC = $(wildcard src/*_test.c)
OBJ = $(SRC:.c=.o)
TEST_OBJ = $(TEST_SRC:.c=.o)
TEST_BIN = $(patsubst src/%,tests/%,$(TEST_SRC:.c=.test))
all: $(NAME)
# ...
check: $(TEST_BIN)
@total=0; success=0; failure=0; \
for test in $^; do \
./$$test; \
exit_code=$$?; \
if [ $$exit_code -eq 0 ]; then \
success=$$((success+1)); \
else \
failure=$$((failure+1)); \
fi; \
total=$$((total+1)); \
done; \
echo "============================================================"; \
echo "test summary"; \
echo "============================================================"; \
echo "# TOTAL: $$total"; \
echo "# PASS: $$success"; \
echo "# FAIL: $$failure"; \
echo "============================================================";
%.o: %.c
$(CC) $(CFLAGS) -c $< -o $@
tests/%_test.test: src/%_test.o $(filter-out %_test.o, $(OBJ))
@mkdir -p tests
$(CC) $(CFLAGS) $^ -o $@
clean:
rm -f $(OBJ) $(TEST_OBJ)
rm -rf tests
.PHONY: all clean test
.SECONDARY: $(TEST_OBJ)
This is a pretty simple test framework, is just some .h
file, there are tons of ways to make it work with your project, so you can just use the .h
and implement the automatic execution of the tests in a way that fits your project! :D