Skip to content

A simple unit test framework for C and ASM in C.

Notifications You must be signed in to change notification settings

izenynn/mini-unit

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

23 Commits
 
 
 
 
 
 
 
 

Repository files navigation

mini-unit

Contents

Info

A simple unit test framework for C and ASM in C.

Written in just one small .h! :D

Usage

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_CASEs and ASSERTs 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 ASSERTs in one TEST_CASE, do more TEST_CASEs, and since this is just C with macros, you can do whatever you want.

Just renember to call the TEST_CASEs 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.

Automatic tests execution

With the provided Makefile

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

An example of a custom Makefile

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)

Other

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

forthebadge forthebadge