Compile the C test runner


A minimal starting point
Let's get a Unity test runner to compile!
The Concept: Reduce code complexity
As outlined in TDD in C: Part 0, I won't try to anticipate what the next piece of missing boilerplate, filesystem support, tooling or user code may be. Primarily, I will let build and test failures guide development instead of hunches about upcoming requirements or 'necessary' complexity.
Applying the concept
What does the concept of focusing on satisfying a requirement with the least amount of code complexity imply for our current project? The answer is quite simple: we try to use the least amount of code complexity possible to get a TDD workflow going in C.
What is a key part of a TDD workflow in C? A test runner. Well, what does the Unity framework's test runner need 'to get going'? Since the Unity framework is pure C, a Unity test runner must have an entry point under the hood somewhere: a main
function.
The Unity documentation says the following boilerplate is the entry point for a test runner:
What if we try using a test file that contains just that main
function? We suspend thoughts about whether it is sufficient to compile, whether our dependencies are installed, etc and take this as a minimal starting point.
main
entry point', we can use GitHub's search feature to find candidate starting points: repo:ThrowTheSwitch/Unity "int main("
The Commits
feat: add Unity to project
I'm starting with an empty repository: TDD-with-Unity.
1. I create test_that_unity_works.c
. This is my test file. It has the main
function.
2. I attempt to compile:gcc test_that_unity_works.c -o unity_test_runner.out
Unsurprisingly, I get warnings and errors that need to be fixed.
test_that_something_happens
caused an 'undeclared' error.UNITY_BEGIN
, RUN_TEST
and UNITY_END
caused implicit declaration warnings.3. I stage and commit the change.
fix: declare test function
At this point, all I want is for my minimal unity test runner to compile. I don't need to anticipate implementation details beyond that. If a change is sufficient to remove an error or warning, it is enough.
1. I add an empty function to test_that_unity_works.c
.
2. I check to see if I am one step closer to compiling:gcc test_that_unity_works.c -o unity_test_runner.out
I still get the warnings about the test suite management macros.
UNITY_BEGIN
, RUN_TEST
and UNITY_END
caused implicit declaration warnings.But I no longer get the 'undeclared' error. I've also progressed along the compile toolchain - I have a linking error now instead:
UNITY_BEGIN
, RUN_TEST
and UNITY_END
macros.We are one step closer.
3. I stage, commit and push:
main
with just UNITY_BEGIN
and UNITY_END
- just the test runner macros. Not a test runner and test cases.chore: add Unity as submodule
1. From the repository root, I add the Unity framework as a submodule:git submodule add
https://github.com/ThrowTheSwitch/Unity.git
Unity
unity.c
, unity.h
and unity_internals.h
. Although the Unity repository contains more than that (documentation, plugins, examples, self-tests, and so on) and there are quality-of-life script options available, core Unity is those three files and nothing else. The macros will be in them.2. I confirm that the Unity dependencies are in the filesystem:find -name unity.c -o -name unity.h -o -name unity_internals.h
3. I stage, commit and push.
4. In a different, non-nested directory, I use git clone --recurse-submodules
to check that the repository will supply a collaborator with the Unity dependencies:
I expect the find
command to return three entries and it does.
docs: add clone How To
1. I add a quick note to the README.md
about how to clone the project.
fix: include Unity dependencies
I now move on to fixing the implicit declaration warnings for the test suite management macros.
1. I add #include "unity.h"
to test_that_unity_works.c
.
2. I attempt to compile:gcc -I./Unity/src test_that_unity_works.c ./Unity/src/unity.c -o unity_test_runner.out
setUp
and tearDown.
Great. We have eliminated the warnings about the test suite management macros. A linker error has replaced it. This is progress.
3. I stage, commit and push.
fix: define setUp and tearDown
Again, I focus on defining only what is needed to make the code compile.
1. I define tearDown
and setUp
in test_that_unity_works.c
with empty function bodies.
2. I attempt to compile:gcc -I./Unity/src test_that_unity_works.c ./Unity/src/unity.c -o unity_test_runner.out
There are no warnings and no errors. unity_test_runner.out
compiles and runs.
3. I stage, commit and push.
The Replit
This is the state of the project after doing all the commits in this blog post. When compiled, the file test_that_unity_works.c
becomes the test runner. It will execute the tests defined in the file so long as those test functions are included in the main
function as an argument to a RUN_TEST
macro.
Next: A Deep Dive
The next article in the series will be a deep-dive on the test suite management macros (BEGIN_UNITY
, RUN_TEST
and UNITY_END
).
Subscribe to my newsletter
Read articles from Warren Markham directly inside your inbox. Subscribe to the newsletter, and don't miss out.
Written by

Warren Markham
Warren Markham
I've worked in an AWS Data Engineer role at Infosys, Australia. Previously, I was a Disability Support Worker. I recently completed a course of study in C and Systems Programming with Holberton School Australia. I'm interested in collaborative workflows and going deeper into TDD, automation and distributed systems.