How to integrate the µTest++ Testing Framework
As an xpm package, the most convenient method to integrate the µTest++ Testing Framework into a project is to add it as a dependency via xpm.
However, as with any source code library, this project may also be integrated into another project in the traditional manner, either by copying the relevant files into the target project, or by linking the entire project as a Git submodule.
xpm packages (xPacks) refresher
xpm packages, abbreviated as xPacks, are general-purpose,
language-neutral software packages.
They use the same format as npm packages,
which comprises a collection of files/folders
and a package.json file with the package metadata.
xpm can install source and binary packages.
For more details, see the explanation on the Getting Started page.
Automated installation
Alongside the source files, this project also includes a package.json
file containing the metadata that identifies it as an xpm/npm
package, enabling direct installation from GitHub or
from the npmjs.com registry as
@micro-os-plus/micro-test-plus.
Prerequisites
The only requirement for an automated installation is a recent xpm, which is a portable Node.js command line application that complements npm with several additional features specific to C/C++ projects.
To install xpm, follow the instructions on the xpm install page.
If already installed, it is recommended to update it to the latest version with:
npm install --location=global xpm@latest
Although not mandated by xpm, it is also recommended to upgrade npm to the latest version, and node to a currently supported LTS version.
Local installations
One of the xPack design goals is to allow each project to select the exact versions of the libraries it requires.
Similarly to npm being able to install specific versions of the JavaScript tools into each project, xpm was also designed to be able to install specific versions of the required libraries locally into each project.
Therefore, similarly to the way npm installs the JavaScript packages into
node_modules, xpm installs the libraries into
xpacks. Here there will be separate folders with the installed
packages, for example
xpacks/@micro-os-plus/micro-test-plus.
Initialise the project
The project needs a package.json file in its root folder.
Create it by running xpm init in the project folder (replace my-project
with the name of the folder):
cd my-project
xpm init
Under the hood
The primary purpose of xpm init is to create a package.json file, if not
already present.
In addition to name and version, the minimal package.json must
include a property named xpacks, even if empty. This property is
mandatory to identify the package as an xpm package.
Installation via xpm
The next step is to install the micro-test-plus package into the project.
The command to install the latest available version of micro-test-plus is:
xpm install @micro-os-plus/micro-test-plus@latest --verbose
To install a specific version, specify it explicitly:
xpm install @micro-os-plus/micro-test-plus@6.0.0 --verbose
Installation details
The above xpm install command will perform the following:
- identify the desired version
of @micro-os-plus/micro-test-plus, download it into a cache and unpack
it into a versioned folder
within the user's global xPacks store (if not already present);
check the output of the
xpm installcommand for the actual folder used on your platform; - create a local symbolic link
such as
xpacks/@micro-os-plus/micro-test-pluspointing to the versioned folder in the user's global xPacks store; - add
@micro-os-plus/micro-test-plustopackage.jsonas a dependency; this associates a specific version of µTest++ Testing Framework with the current project (details below).
The installation location may be configured using the
XPACKS_STORE_FOLDER environment variable; for more details, see the
xpm folders page.
Reproducibility and dependencies
To ensure reproducibility, it is essential for each project to always use the exact desired versions of the required libraries, regardless of the libraries installed in the system.
To achieve this objective, xpm records all locally installed packages
as dependencies in the project package.json file.
The result appears as follows:
"xpack": {
"minimumXpmRequired": "0.23.3",
"dependencies": {
"@micro-os-plus/micro-test-plus": {
"specifier": "6.0.0",
"local": "link",
"platforms": "all"
}
},
"devDependencies": {},
"properties": {},
"actions": {},
"buildConfigurations": {}
}
If the package.json is saved in the revision system, the above
definition acts as a firm reference to the specific version of
µTest++ Testing Framework.
After cloning the project into a different location, the command xpm install
may be used to install all dependencies.
This is particularly useful for CI/CD environments.
Install folder hierarchy
Following the xpacks/@micro-os-plus/micro-test-plus link, the installed
package is a folder hierarchy that includes only the source files of the
library, the include folder with the public headers, and the build system
files (CMakeLists.txt, meson.build, and xcdl-package.jsonc) at the top
level.
% tree -l
.
├── CHANGELOG.md
├── CMakeLists.txt
├── include
│ └── micro-os-plus
│ ├── micro-test-plus
│ │ ├── check-result.h
│ │ ├── counters.h
│ │ ├── deprecated.h
│ │ ├── detail.h
│ │ ├── exceptions.h
│ │ ├── expression-formatter.h
│ │ ├── extension.h
│ │ ├── function-comparators.h
│ │ ├── inlines
│ │ │ ├── check-result-inlines.h
│ │ │ ├── counters-inlines.h
│ │ │ ├── deprecated-inlines.h
│ │ │ ├── detail-inlines.h
│ │ │ ├── exceptions-inlines.h
│ │ │ ├── expression-formatter-inlines.h
│ │ │ ├── function-comparators-inlines.h
│ │ │ ├── math-inlines.h
│ │ │ ├── reflection-inlines.h
│ │ │ ├── reporter-inlines.h
│ │ │ ├── runner-inlines.h
│ │ │ ├── runner-options-inlines.h
│ │ │ ├── stopwatch-inlines.h
│ │ │ ├── test-inlines.h
│ │ │ └── utility-inlines.h
│ │ ├── math.h
│ │ ├── README.md
│ │ ├── reflection.h
│ │ ├── reporter-human.h
│ │ ├── reporter-tap.h
│ │ ├── reporter.h
│ │ ├── runner-options.h
│ │ ├── runner.h
│ │ ├── stopwatch.h
│ │ ├── test.h
│ │ └── utility.h
│ └── micro-test-plus.h
├── LICENSE
├── LICENSE-Boost
├── meson.build
├── package.json
├── README.md
├── src
│ ├── check-result.cpp
│ ├── counters.cpp
│ ├── deprecated.cpp
│ ├── expression-formatter.cpp
│ ├── reporter-human.cpp
│ ├── reporter-tap.cpp
│ ├── reporter.cpp
│ ├── runner-options.cpp
│ ├── runner.cpp
│ ├── stopwatch.cpp
│ ├── test.cpp
│ └── utility.cpp
└── xcdl-package.jsonc
6 directories, 55 files
The original Git repository contains hundreds of additional files, such as the website files and the multi-platform tests; therefore, the installed package is a much smaller subset of the original project and is recommended.
Integration
This project is implemented in C++. Tests are also expected to be written in C++, although the code under test may be written in standard C.
The source code has been compiled natively using GCC and LLVM/clang, and cross-compiled for embedded Arm and RISC-V targets, with no warnings.
For execution on embedded platforms, the test framework requires only minimal system support: the ability to write to an output stream. Any environment providing this capability is suitable; for standalone tests, the most common approach is semihosting.
Pre-configured CMake and Meson build files are provided to simplify integration into user projects, as described below. For alternative build systems, refer to the sections that follow.
Include folders
The following folder should be passed to the compiler during the build process:
include
The primary header file to include in user projects is:
#include "micro-os-plus/micro-test-plus.h"
No other header file should be included explicitly by the application.
Source files
All source files in the src folder should be incorporated into user
projects. The files are:
check-result.cppcounters.cppdeprecated.cppexpression-formatter.cppreporter-human.cppreporter-tap.cppreporter.cpprunner-options.cpprunner.cppstopwatch.cpptest.cpputility.cpp
The library must be built with the same exception setting as the
application: the layout of the object returned by expect() and
require() depends on whether exceptions are enabled, so the
translation units compiled with and without exceptions cannot be mixed.
Compiler options
The following options must be supplied to the compiler:
-std=c++20or later for C++ source files
Dependencies
This library has no required dependencies.
The µOS++ Tracing Infrastructure
is optional, and is used only to output trace messages in Debug mode. The
library includes micro-os-plus/diag/trace.h only if it is available, so to
enable the trace messages, install the @micro-os-plus/diag-trace package, add
it to the build of the application, and define the trace macros
(see Configuration). The CMake and
Meson files of this library do not link it.
Static suites
The test suites of the application, defined as static_suite objects, must not
be packed in a static library, however µTest++ itself is built (see the
FAQ).
CMake
To integrate the micro-test-plus library into a CMake application, add the folder where this project is located to the build:
add_subdirectory("xpacks/@micro-os-plus/micro-test-plus")
The result is an interface library, whose sources are compiled in each target that links it, and that may be added as an application dependency with:
target_link_libraries(your-target PRIVATE
micro-os-plus::micro-test-plus
)
CMake language standard
The library requires C++20, but its CMake files do not select it. Set the
CMAKE_CXX_STANDARD variable in the project, before the
add_subdirectory() call shown above:
set (CMAKE_CXX_STANDARD 20)
set (CMAKE_CXX_STANDARD_REQUIRED ON)
Without CMAKE_CXX_STANDARD_REQUIRED, CMake may silently fall back to an older
standard if the compiler does not support C++20.
CMake library targets
The CMakeLists.txt file defines three libraries, which differ in how the
µTest++ sources are built, and in the options that the sources get; all of them
provide the same headers and the same definitions.
| Target | Library | Sources |
|---|---|---|
micro-os-plus::micro-test-plus | interface | compiled in each target that links it |
micro-os-plus::micro-test-plus-objects-library | object | compiled once, and the object files are shared by the targets that link it |
micro-os-plus::micro-test-plus-static-library | static | compiled once, into an archive (named micro-test-plus) linked into each target |
Use the interface library, as shown above, for a single application. When several executables use µTest++, as the tests of this project do, the object or the static library avoids compiling the sources again for each executable. Like the interface library, they are excluded from the default build; they are built when a target links them.
CMake common options
The interface library is compiled in the target of the application, so its
sources automatically get the include folders, the compile definitions, and the
compile options of that target. The object and the static libraries are
separate targets, which do not inherit them: they must be given exactly the
same common options as the application, otherwise the library and the
application are built differently. This matters in particular for the folder of
the micro-os-plus/micro-test-plus-defines.h header, which enables the library
(see Configuration), since the sources of the library are
empty without it, and the application then fails to link, with undefined
symbols. It matters also for the options that change the generated code, such
as -fno-exceptions (see above).
A simple way to give the same options to the application and to the library is
to collect them in an interface library of the project, and link it to both.
The library must be linked by its real name,
micro-os-plus-micro-test-plus-objects-library or
micro-os-plus-micro-test-plus-static-library, since CMake does not allow the
aliases to be modified:
add_library (app-common-options INTERFACE)
# The folder with micro-os-plus/micro-test-plus-defines.h.
target_include_directories (app-common-options INTERFACE "include")
# The common compile options for the application and the library.
target_compile_options (app-common-options INTERFACE -fno-exceptions ...)
add_subdirectory ("xpacks/@micro-os-plus/micro-test-plus")
target_link_libraries (
micro-os-plus-micro-test-plus-static-library PRIVATE app-common-options
)
add_executable (your-target main.cpp)
target_link_libraries (
your-target PRIVATE app-common-options
micro-os-plus::micro-test-plus-static-library
)
Meson
To integrate the micro-test-plus library into a Meson application, add the folder where this project is located to the build:
subdir('xpacks/@micro-os-plus/micro-test-plus')
The result is a dependency object that may be added to an application with:
exe = executable(
'your-target',
sources: ['main.cpp'],
dependencies: [
micro_os_plus_micro_test_plus_dependency,
]
)
Due to differences in the build model, the Meson configurations currently do
not support the object and static library targets for µTest++. They rely on the
interface library approach, where the sources are compiled directly into each
target that links them, so the options of the application, including the folder
of the micro-os-plus/micro-test-plus-defines.h header, apply to them
automatically.
Configuration
The build can be configured using the following preprocessor definitions:
MICRO_OS_PLUS_MICRO_TEST_PLUS_ENABLED- to include and enable the µTest++ library in the build; it is required, and must be defined for both the library sources and the application: without it, the headers and the sources compile to nothing, and the application fails to compile, since none of the µTest++ definitions are declaredMICRO_OS_PLUS_MICRO_TEST_PLUS_TRACE_ENABLED- to enable tracing messages specific to the µTest++ libraryMICRO_OS_PLUS_MICRO_TEST_PLUS_TRACE_CONSTRUCTORS_ENABLED- to enable tracing messages for object constructors and destructorsMICRO_OS_PLUS_MICRO_TEST_PLUS_DEPRECATED_ENABLED- to enable the deprecated definitions, which are otherwise not available; define it for the library sources too
The recommended way to define the micro-test-plus specific macros is to use a
separate header file, micro-os-plus/micro-test-plus-defines.h, and define the
macros there (uncomment the desired lines).
// ----------------------------------------------------------------------------
#ifndef MICRO_OS_PLUS_MICRO_TEST_PLUS_DEFINES_H_
#define MICRO_OS_PLUS_MICRO_TEST_PLUS_DEFINES_H_
// ----------------------------------------------------------------------------
// µTest++, a lightweight testing framework for embedded platforms.
#if !defined(MICRO_OS_PLUS_MICRO_TEST_PLUS_ENABLED)
#define MICRO_OS_PLUS_MICRO_TEST_PLUS_ENABLED
#endif // !defined(MICRO_OS_PLUS_MICRO_TEST_PLUS_ENABLED)
// Display trace messages in the µTest++ Testing Framework when TRACE is
// enabled.
#if !defined(MICRO_OS_PLUS_MICRO_TEST_PLUS_TRACE_ENABLED)
// #define MICRO_OS_PLUS_MICRO_TEST_PLUS_TRACE_ENABLED
#endif // !defined(MICRO_OS_PLUS_MICRO_TEST_PLUS_TRACE_ENABLED)
// Display trace messages in constructors and destructors in the µTest++
// testing framework when TRACE is enabled.
#if !defined(MICRO_OS_PLUS_MICRO_TEST_PLUS_TRACE_CONSTRUCTORS_ENABLED)
// #define MICRO_OS_PLUS_MICRO_TEST_PLUS_TRACE_CONSTRUCTORS_ENABLED
#endif // !defined(MICRO_OS_PLUS_MICRO_TEST_PLUS_TRACE_CONSTRUCTORS_ENABLED)
// Enable the deprecated definitions of the µTest++ Testing Framework, which
// are otherwise not available; the compiler reports their use.
#if !defined(MICRO_OS_PLUS_MICRO_TEST_PLUS_DEPRECATED_ENABLED)
// #define MICRO_OS_PLUS_MICRO_TEST_PLUS_DEPRECATED_ENABLED
#endif // !defined(MICRO_OS_PLUS_MICRO_TEST_PLUS_DEPRECATED_ENABLED)
// ----------------------------------------------------------------------------
#endif // MICRO_OS_PLUS_MICRO_TEST_PLUS_DEFINES_H_
// ----------------------------------------------------------------------------
Once the xCDL tool is available, for xCDL enabled projects this file will be generated automatically.
The cdlSettings to enable them are:
"cdlConfigurations": {
//
"<name>": {
...
"cdlSettings": {
...
"micro-os-plus.micro-test-plus.trace": true,
"micro-os-plus.micro-test-plus.trace-constructors": true
}
},
...
}
Alternative installation
Installation via npm
The package may also be installed with npm or related tools, but the features specific to C/C++ projects will not be available, so it is recommended to use xpm.
Copy files
The traditional method of using source libraries is to copy them into the user's project.
The obvious advantage is simplicity, but the disadvantage is that the library becomes part of the project, and any improvements or bug fixes must be manually copied into the project.
Add as a Git submodule
Another common solution is to add the entire project as a Git submodule,
for example beneath an xpacks folder:
cd my-project
git init # Unless already a Git project
mkdir -p xpacks
git submodule add https://github.com/micro-os-plus/micro-test-plus-xpack.git \
xpacks/@micro-os-plus/micro-test-plus
Note that linking the project as a submodule brings the entire project, with tests and documentation, not only the source files.
Installing via xpm filters the content, and only the relevant files are brought into the project.
Uninstall
The xpm packages do not use any form of system installer; instead they are distributed as portable archives; therefore no uninstaller is needed: removing the links, and possibly the user's global xPacks store folder and the user xPack cache folder, is sufficient.
To remove the links created by xpm in the current project, navigate to the project folder:
cd my-project
and request xpm to uninstall the package:
xpm uninstall @micro-os-plus/micro-test-plus --verbose
To completely remove the package from the user's global xPacks store:
xpm uninstall --global @micro-os-plus/micro-test-plus --verbose
Clean-ups
For a complete clean-up, note that xpm uses two folders:
- Windows
- macOS
- GNU/Linux
%APPDATA%\xPacks%LOCALAPPDATA%\Caches\xPacks
${HOME}/Library/xPacks${HOME}/Library/Caches/xPacks
${HOME}/.local/xPacks${HOME}/.cache/xPacks
They can be removed at any time and space reclaimed; xpm will recreate them during new installations.
However, the projects that link to the user's global xPacks store will have broken links.
Status
The micro-test-plus library is production-ready and is used to test multiple projects within the µOS++ framework.