Adding tests to your firmware need not be a chore. With a little time spent on setting up the environment beforehand, tests can run after each compilation to quickly validate any change in expected behaviour.

PREPARATION

Linux Users – Install the required packages from the command line:

sudo apt install gcc python curl https://bootstrap.pypa.io/get-pip.py -o get-pip.py python get-pip.py 
sudo pip install gcovr 
sudo pip install gcovr --upgrade

Windows Users – Install the packages manually:

Use the MinGW package manager to install GCC: http://mingw-w64.org/doku.php
Install python: https://www.python.org/
PIP: https://pypi.org/project/pip/
Gcovr: https://gcovr.com/en/4.1/installation.html
[Note that the examples shown here require gcovr version 4.1]

After installing the above, ensure gcc, make, python and gcovr are available in the system path:

C:\MinGW\bin 
C:\MinGW\msys\1.0\bin 
C:\Users\username\AppData\Local\Programs\Python\Python37-32 C:\Users\username\AppData\Local\Programs\Python\Python37-32\Scripts

On either format, a local clone of Unity is required:

git clone https://github.com/ThrowTheSwitch/Unity.git

TESTING

Tests are made up from different components:

  • Source code under test
  • Unit tests
  • Mocks
  • Test Runners (look in the Unity documentation for more details about these)
  • Unity itself

The following makefile extract shows the build sequence, given two source files business_logic.c and eeprom.c

#unity 
$(C_COMPILER) -c $(CFLAGS) $(INC_DIRS) $(SYMBOLS) $(UNITY_ROOT)/src/unity.c -o unity.o $(C_COMPILER) -c $(CFLAGS) $(INC_DIRS) $(SYMBOLS) $(UNITY_ROOT)/extras/fixture/src/unity_fixture.c -o unity_fixture.o 

#mocks 
$(C_COMPILER) -c $(CFLAGS) $(INC_DIRS) $(SYMBOLS) ./mock/spi_mock.c -o spi_mock.o 

#source files 
$(C_COMPILER) -c $(CFLAGS) $(CFLAGS_COV) $(INC_DIRS) $(SYMBOLS) ../src/business_logic.c -o business_logic.o 
$(C_COMPILER) -c $(CFLAGS) $(CFLAGS_COV) $(INC_DIRS) $(SYMBOLS) ../src/eeprom.c -o eeprom.o 

#test files 
$(C_COMPILER) -c $(CFLAGS) $(INC_DIRS) $(SYMBOLS) ./business_logic_test.c -o business_logic_test.o 
$(C_COMPILER) -c $(CFLAGS) $(INC_DIRS) $(SYMBOLS) ./eeprom_test.c -o eeprom_test.o 

#test runners 
$(C_COMPILER) -c $(CFLAGS) $(INC_DIRS) $(SYMBOLS) ./test_runners/business_logic_test_runner.c -o business_logic_test_runner.o 
$(C_COMPILER) -c $(CFLAGS) $(INC_DIRS) $(SYMBOLS) ./test_runners/eeprom_test_runner.c -o eeprom_test_runner.o $(C_COMPILER) -c $(CFLAGS) $(INC_DIRS) $(SYMBOLS) ./test_runners/all_tests.c -o all_tests.o 

$(C_COMPILER) $(CFLAGS) $(CFLAGS_COV) $(INC_DIRS) $(SYMBOLS) \ 
unity.o \ 
unity_fixture.o \ 
business_logic.o \ 
eeprom.o \ 
spi_mock.o \ 
business_logic_test.o \ 
eeprom_test.o \ 
business_logic_test_runner.o \ 
eeprom_test_runner.o \ 
all_tests.o -o $(TARGET)

Where:

C_COMPILER=gcc 
CFLAGS=-std=c99 
CFLAGS += -Wall 
CFLAGS += -Wextra 
CFLAGS += -Wpointer-arith 
CFLAGS += -Wcast-align 
CFLAGS += -Wwrite-strings 
CFLAGS += -Wswitch-default 
CFLAGS += -Wunreachable-code 
CFLAGS += -Winit-self 
CFLAGS += -Wmissing-field-initializers 
CFLAGS += -Wno-unknown-pragmas 
CFLAGS += -Wstrict-prototypes 
CFLAGS += -Wundef 
CFLAGS += -Wold-style-definition 
CFLAGS += -DUNIT_TEST 
CFLAGS_COV=-fprofile-arcs 
CFLAGS_COV+=-ftest-coverage

Notice the DUNIT_TEST flag, this allows the source files to abstract away any hardware dependencies and use mocks in their place.

Hopefully there now exists an executable which can be ran. Launching the executable will show how many test passes and failures exist.

./test.exe Unity test run 1 of 1 …….
-----------------------
7 Tests 0 Failures 0 Ignored OK

Now get the test coverage using gcovr

gcovr -r . --html-details -o index.html gcovr -r . -s