- Part 1: Reference
- Part 2: Optional Explanatory Examples
Because we use CMake to build ApprovalTests.cpp, we also provide integration points for our users.
Approval Tests' CMake build exports an interface target ApprovalTests::ApprovalTests
. Linking
against it will add the proper include path and all necessary capabilities
to the resulting binary.
This target is provided when ApprovalTests.cpp is used as a subdirectory.
Assuming that ApprovalTests.cpp has been cloned to lib/ApprovalTests.cpp
:
add_subdirectory(lib/ApprovalTests.cpp)
target_link_libraries(tests ApprovalTests::ApprovalTests)
ApprovalTests.cpp's CMake project also provides some options for other projects that consume it.
They are:
- Options to control what targets are built.
- Note that these are always built if this is the top-level project.
APPROVAL_TESTS_BUILD_TESTING
-- WhenON
, the self-tests are run. Defaults toOFF
.APPROVAL_TESTS_BUILD_EXAMPLES
-- WhenON
, the examples are run. Defaults toOFF
.
- Options to control which of our copies of header-only third_party libraries are made available.
- Note that these are always included if this is the top-level project.
APPROVAL_TESTS_BUILD_THIRD_PARTY_CATCH2
-- WhenON
, this project's copy of the Catch2 test framework is included. Defaults toOFF
.APPROVAL_TESTS_BUILD_THIRD_PARTY_DOCTEST
-- WhenON
, this project's copy of the doctest test framework is included. Defaults toOFF
.APPROVAL_TESTS_BUILD_THIRD_PARTY_UT
-- WhenON
, this project's copy of the Boost.UT test framework is included. Defaults toOFF
.
- Options to control the behaviour of our builds.
APPROVAL_TESTS_ENABLE_CODE_COVERAGE
-- WhenON
, Approval Test's own tests are run with code coverage enabled. This uses Lars Bilke's CodeCoverage.cmake. Defaults toOFF
.
The file CMake/ApprovalTestsOptions.cmake defines these options.
add_subdirectory()
- See Use own ApprovalTests.cpp and Catch2 clones below, for an example using
add_subdirectory()
. - Use case: This is typically for you have your own copy of the Approval Tests project directory that you want to re-use.
- See Use own ApprovalTests.cpp and Catch2 clones below, for an example using
FetchContent
- See Make CMake clone ApprovalTests.cpp and Catch2
below, for an example using the
FetchContent
module. - The examples below use
FetchContent_MakeAvailable()
, which requires CMake 3.14 or above. - If you only have CMake 3.11 or above, see FetchContent (CMake 3.11+) for how to use
FetchContent_Populate()
. - Use case: This is typically for when you want CMake to download a specific version of Approval Tests for you, behind the scenes.
- See Make CMake clone ApprovalTests.cpp and Catch2
below, for an example using the
ExternalProject
- With CMake before 3.11, see the
ExternalProject
module. TheFetchContent
examples below should help get started withExternalProject
. - Use case: This is typically for when you want CMake to download a specific version of Approval Tests for you, behind the scenes, and you are using an older version of CMake.
- With CMake before 3.11, see the
find_package()
- not supported- There is not yet support for
find_package()
.
- There is not yet support for
There are two main options for incorporating Approval Tests in to your project:
- Download the single-header file from the Releases page and, typically, add the header to your source code.
- Obtain a copy of the entire ApprovalTests.cpp repository and incorporate it in to your CMake build scripts.
Options for obtaining the repository typically include:
- cloning it
- forking it
- including it as a sub-repository
- having a build tool, such as CMake, download it for you automatically as part of your builds
We recommend using the CMake integration route, which has several user benefits over the single header:
- Automatic prevention of most of the scenarios listed in Troubleshooting Misconfigured Build.
- Source-code compatibility with the single header download:
- For convenience, we provide a wrapper header file ApprovalTests.hpp, which can be used to access all the features of this library, without having to know which features are provided by which header files.
- Flexibility in how many of the Approval Tests include files you include:
- There is also the option to include just the headers in ApprovalTests/ that you use.
- This may slightly improve build speeds.
- It may occasionally provide workarounds to bugs.
Example Project
Suppose you are writing some tests that use ApprovalTests.cpp with the Catch2 test framework.
Your top-level CMakeLists.txt
file might look something like this:
cmake_minimum_required(VERSION 3.14 FATAL_ERROR)
# This version is needed for FetchContent_Declare & FetchContent_MakeAvailable
project(fetch_content_approvaltests)
enable_testing()
add_subdirectory(dependencies)
add_subdirectory(tests)
The important thing to note, for following the examples below, is the add_subdirectory(dependencies)
line. It makes CMake load a file dependencies/CMakeLists.txt
.
Each example below shows a dependencies/CMakeLists.txt
, for the corresponding scenario. All other code is identical between the example directories.
Here is this example project.
Example Tests
Your tests/CMakeLists.txt
file might look something like this:
add_executable(tests
main.cpp
tests.cpp
)
target_link_libraries(tests ApprovalTests::ApprovalTests Catch2::Catch2)
target_compile_features(tests PUBLIC cxx_std_11)
set_target_properties(tests PROPERTIES CXX_EXTENSIONS OFF)
add_test(
NAME tests
COMMAND tests)
This says that the libraries ApprovalTests::ApprovalTests
and Catch2::Catch2
are required by the tests
executable.
Here is this example project's test directory.
Dependencies
How might you enable CMake to provide those libraries? In other words, what are the options for the contents of dependencies/CMakeLists.txt
?
The next few sections describe some options.
Note: The files in this section can be viewed and downloaded from fetch_content_approvaltests_catch2.
The following is for when you just want ApprovalTests.cpp and Catch2 to be downloaded as part of your project's build. You don't particularly want to see their source code, although you're happy if your debugger steps in to them.
It also needs CMake 3.14 or above.
We use this dependencies/CMakeLists.txt
file:
# Needs CMake 3.14 or above
include(FetchContent)
# -------------------------------------------------------------------
# ApprovalTests.cpp
FetchContent_Declare(ApprovalTests
GIT_REPOSITORY https://github.com/approvals/ApprovalTests.cpp.git
GIT_TAG master)
FetchContent_MakeAvailable(ApprovalTests)
# -------------------------------------------------------------------
# Catch2
FetchContent_Declare(Catch2
GIT_REPOSITORY https://github.com/catchorg/Catch2.git
GIT_TAG v2.11.1)
FetchContent_MakeAvailable(Catch2)
Note the GIT_TAG
values: This tells CMake which revision of dependencies to use. The value can be a tag or a git commit ID. Here we use master
, to always test our integrations with the latest Approval Tests code. However, it is generally recommended to pin your dependencies to specific versions, and test behaviour before updating to newer versions.
After CMake has generated the build files, the directory structure would look something like this, where the cmake-build-debug
directory is the build space, and the cmake-build-debug/_deps
contains the downloaded and built ApprovalTests.cpp and Catch2 repositories:
fetch_content_approvaltests_catch2/
.git/
cmake-build-debug/
_deps/
approvaltests-build/
approvaltests-src/
approvaltests-subbuild/
catch2-build
catch2-src
catch2-subbuild
...
CMakeLists.txt
dependencies/
CMakeLists.txt
tests/
...
Note: The files in this section can be viewed and downloaded from fetch_content_approvaltests.
The only difference between the previous example and this one is that here we use the Catch2 header that is in the ApprovalTests.cpp project.
We use this dependencies/CMakeLists.txt
file:
# Needs CMake 3.14 or above
include(FetchContent)
# -------------------------------------------------------------------
# ApprovalTests.cpp
FetchContent_Declare(ApprovalTests
GIT_REPOSITORY https://github.com/approvals/ApprovalTests.cpp.git
GIT_TAG master)
# Tell the ApprovalTests CMake files that we want to use its copy of Catch2:
set(APPROVAL_TESTS_BUILD_THIRD_PARTY_CATCH2 ON CACHE BOOL "")
FetchContent_MakeAvailable(ApprovalTests)
We have set APPROVAL_TESTS_BUILD_THIRD_PARTY_CATCH2
to ON
, so that CMake will use the copy of Catch2 that is included in the ApprovalTests.cpp repository.
There are also options to enable use of ApprovalTests.cpp's copies of all other supported test frameworks except GoogleTest, including:
APPROVAL_TESTS_BUILD_THIRD_PARTY_DOCTEST
APPROVAL_TESTS_BUILD_THIRD_PARTY_UT
Note: The files in this section can be viewed and downloaded from add_subdirectory_approvaltests_catch2.
Here, instead of getting CMake to download ApprovalTests.cpp and Catch2, we have got our own clones or forks of them, which we want to use with our own tests.
In this example, the directory structure looks like this:
ApprovalTests.cpp/
.git/
CMakeLists.txt
...
Catch2/
.git/
CMakeLists.txt
...
add_subdirectory_approvaltests_catch2/
.git/
CMakeLists.txt
dependencies/
CMakeLists.txt
tests/
We use this dependencies/CMakeLists.txt
file:
# -------------------------------------------------------------------
# ApprovalTests.cpp
add_subdirectory(
../../ApprovalTests.cpp
${CMAKE_CURRENT_BINARY_DIR}/approvaltests.cpp_build
)
# -------------------------------------------------------------------
# Catch2
set(CATCH_BUILD_TESTING OFF CACHE BOOL "")
add_subdirectory(
../../Catch2
${CMAKE_CURRENT_BINARY_DIR}/catch2_build
)
Here we use add_subdirectory()
. This works with older versions of CMake, unlike the FetchContent
examples above.
The above was tested with CMake 3.8.
If your directory layout differed from the above, you would change the relative paths in the add_subdirectory()
lines.
To save space and repetition, the examples above only show the Catch2 test framework.
The same principles apply when using all the other test frameworks supported by ApprovalTests.cpp.
Note: The files in this section can be viewed and downloaded from develop_approvaltests.
For Approval Tests project maintainers, it is useful to be able to edit and debug both this project and the test frameworks that it depends upon. It helps to be able to see the source of these frameworks, rather than just the single-header releases that are copied in to the third_party directory here.
This also allows us to checkout different commits of any of these projects.
Here we want to enable and run all the ApprovalTests.cpp tests, unlike the cases above, where we only want to run the tests of the project that is being developed.
Consider this directory structure, where the repositories for all these projects are checked out side-by-side, and there is an extra directory develop_approvaltests/
that will contain just a CMakeLists.txt
file, to set up a project containing all the other directories:
ApprovalTests.cpp/
.git/
CMakeLists.txt
...
Catch2/
.git/
CMakeLists.txt
...
doctest/
.git/
CMakeLists.txt
...
googletest/
.git/
CMakeLists.txt
...
ut/
.git/
CMakeLists.txt
...
develop_approvaltests/
CMakeLists.txt
The file develop_approvaltests/CMakeLists.txt
creates a kind of "super build": one project for developing ApprovalTests.cpp and all the projects it depends on:
cmake_minimum_required(VERSION 3.8 FATAL_ERROR)
project(develop_approvaltests)
enable_testing()
# -------------------------------------------------------------------
# Catch2
set(CATCH_BUILD_TESTING OFF CACHE BOOL "")
add_subdirectory(
../Catch2
${CMAKE_CURRENT_BINARY_DIR}/catch2_build
)
# -------------------------------------------------------------------
# doctest
add_subdirectory(
../doctest
${CMAKE_CURRENT_BINARY_DIR}/doctest_build
)
# -------------------------------------------------------------------
# GoogleTest
# Prevent GoogleTest from overriding our compiler/linker options
# when building with Visual Studio
set(gtest_force_shared_crt ON CACHE BOOL "" )
add_subdirectory(
../googletest
${CMAKE_CURRENT_BINARY_DIR}/googletest_build
)
# -------------------------------------------------------------------
# Boost.ut
set(BUILD_BENCHMARKS OFF CACHE BOOL "")
set(BUILD_EXAMPLES OFF CACHE BOOL "")
set(BUILD_TESTS OFF CACHE BOOL "")
add_subdirectory(
../ut
${CMAKE_CURRENT_BINARY_DIR}/ut_build
)
if ("${CMAKE_CXX_COMPILER_ID}" MATCHES "Clang")
# Turn off some checks for extensions needed for Boost.ut
target_compile_options(boost.ut INTERFACE
-Wno-c99-extensions # Needed for Boost.ut, at least in v1.1.6
)
endif()
# -------------------------------------------------------------------
# ApprovalTests.cpp
set(APPROVAL_TESTS_BUILD_TESTING ON CACHE BOOL "")
set(APPROVAL_TESTS_BUILD_EXAMPLES ON CACHE BOOL "")
add_subdirectory(
../ApprovalTests.cpp
${CMAKE_CURRENT_BINARY_DIR}/approvaltests.cpp_build
)