PicoTest is a single-file unit testing framework for C programs that follows the xUnit principles:
https://en.wikipedia.org/wiki/XUnit
PicoTest is released under the terms of the The 3-Clause BSD License:
https://opensource.org/licenses/BSD-3-Clause
PicoTest is a single-file package, everything is defined in the header file
picotest.h
. So you can either install this file in a standard location, or
copy it within your project source tree.
Simply include the file in your source file, then start writing your tests!
#include <picotest.h>
The complete documentation is available here:
https://fredericbonnet.github.io/picotest
The documentation site was built using these great tools:
- Doxygen extracts the documentation from the source code as both HTML and XML formats (the raw HTML output is available here)
- seaborg converts the XML files to Markdown (full disclosure: I'm the author of this tool!)
- docsify generates the documentation site from the Markdown files
To rebuild the documentation you'll need the following tools:
- Doxygen to process the provided
Doxyfile
and parse the source code - Node.js to run the build scripts:
npm run docs
If you want to serve the documentation locally you can use the provided script:
npm run docsify
The examples
subdirectory contains several example source files that
demonstrate the various features of PicoTest. These examples are also integrated
in the documentation.
Building the examples requires the CMake build tool along with your favorite toolchain:
PicoTest is self-tested and comes with a complete test suite that covers all aspects of the framework. This guarantees that PicoTest is production-ready.
The test suite itself is a good real-world example of PicoTest in action.
Building and running the test suite requires CMake (see next section for more information). To build the suite:
cd tests
cmake -S . -B build
cmake --build build
The build process makes use of the test discovery mechanism described in the next section.
To run the suite using CTest:
cd tests/build
ctest
You can also run the suite executable test_picotest
directly from the CMake
output directory.
PicoTest provides a CMake module definition for easier integration with other CMake projects. In particular, it comes with an auto-discovery script for CTest that makes use of the test traversal features of PicoTest.
The file FindPicoTest.cmake
is the module definition. Add this file to your
CMAKE_MODULE_PATH
, and add the following line to your CMake project:
find_package(PicoTest)
You can then add the PicoTest
dependency to your targets, e.g.:
add_executable(my_test_runner)
target_link_libraries(my_test_runner
PRIVATE PicoTest
)
If you also use CTest for test automation with enable_testing()
, you can also
call the provided picotest_discover_tests
macro to integrate PicoTest test
cases in your build process automatically. For example, assuming that the
my_test_runner
executable:
- when passed the
-l
option, will list all its test cases using thePICOTEST_TRAVERSE
feature. - when passed
<test_name>
, will execute the matching test case.
Then the following lines will:
- execute
my_test_runner -l
as a post-build command tomy_test_runner
, - add each discovered test case using
add_test(<test_name>)
, - when invoking the
test
rule, execute each test unitarily withmy_test_runner <test_name>
.
enable_testing()
picotest_discover_tests(my_test_runner
TEST_LIST_OPTION "-l"
)
PicoTest was developed on Windows 10 and Linux Ubuntu 16.04 using the following tools:
- IDE: Visual Studio Code
- Build tool: CMake 3.15.2
- Windows toolchain: Microsoft Visual C++ Build Tools 14
- Linux toolchain: GCC 5.4.0
It should work with any reasonably modern C compiler that supports variadic macros.
The assertion mechanism relies on setjmp()
/ longjmp()
. While these
functions are discouraged for production code, their usage is acceptable in the
context of unit testing: in our case, longjmp()
is only called when an
assertion fails, a situation where the actual process state is no longer
reliable anyway. Moreover, they constitute the only standard exception handling
mechanism for plain C code.