Catch2

Framework

catchorg/Catch2

A modern C++ test framework supporting unit tests, TDD, BDD, and microbenchmarking.

Overview

Catch2 is a C++ test framework that offers simple and natural test writing, with sections for setup/teardown, BDD macros, and basic microbenchmarking. It has no external dependencies and is available as a single-header or a compiled library.

README Preview

\n\n\n[](https://github.com/catchorg/catch2/releases)\n[](https://github.com/catchorg/Catch2/actions/workflows/linux-simple-builds.yml)\n[](https://github.com/catchorg/Catch2/actions/workflows/linux-other-builds.yml)\n[](https://github.com/catchorg/Catch2/actions/workflows/mac-builds.yml)\n[](https://ci.appveyor.com/project/catchorg/catch2)\n[](https://codecov.io/gh/catchorg/Catch2)\n[](https://godbolt.org/z/EdoY15q9G)\n[](https://discord.gg/4CWS9zD)\n\n\n## What is Catch2?\n\nCatch2 is mainly a unit testing framework for C++, but it also\nprovides basic micro-benchmarking features, and simple BDD macros.\n\nCatch2's main advantage is that using it is both simple and natural.\nTest names do not have to be valid identifiers, assertions look like\nnormal C++ boolean expressions, and sections provide a nice and local way\nto share set-up and tear-down code in tests.\n\n**Example unit test**\n```cpp\n#include \n\n#include \n\nuint32_t factorial( uint32_t number ) {\n    return number \n#include \n\n#include \n\nuint64_t fibonacci(uint64_t number) {\n    return number < 2 ? number : fibonacci(number - 1) + fibonacci(number - 2);\n}\n\nTEST_CASE("Benchmark Fibonacci", "[!benchmark]") {\n    REQUIRE(fibonacci(5) == 5);\n\n    REQUIRE(fibonacci(20) == 6'765);\n    BENCHMARK("fibonacci 20") {\n        return fibonacci(20);\n    };\n\n    REQUIRE(fibonacci(25) == 75'025);\n    BENCHMARK("fibonacci 25") {\n        return fibonacci(25);\n    };\n}\n```\n\n_Note that benchmarks are not run by default, so you need to run it explicitly\nwith the `[!benchmark]` tag._\n\n\n## Catch2 v3 has been released!\n\nYou are on the `devel` branch, where the v3 version is being developed.\nv3 brings a bunch of significant changes, the big one being that Catch2\nis no longer a single-header library. Catch2 now behaves as a normal\nlibrary, with multiple headers and separately compiled implementation.\n\nThe documentation is slowly being updated to take these changes into\naccount, but this work

FAQ (5)

Troubleshooting
How to fix Catch2 v3.16.0 not re-enabling optimizations under MSVC due to wrong _MSVC_VER macro?

In the Catch2 amalgamated header (for example catch_amalgamated.hpp), go to line 1523 and replace the incorrect macro _MSVC_VER with _MSC_VER in the preprocessor check that guards the pragma re-enabling optimizations. Then rebuild your project. Example correction: change #if defined(_MSVC_VER) to #if defined(_MSC_VER). This issue was introduced in commit 45f9ea1e798c2e128dcba53602ccbddfe5676f6f; use a patched release when available or keep the local header fix as a workaround.

GitHub Issue #3211
Troubleshooting
How do I print extra Catch2 diagnostic output only when a failing test is run through CTest?

Use a Catch2 event listener instead of INFO()/WARN() with -s. Store diagnostics in a global or thread-safe singleton, then write them to stderr from testCaseEnded() only when the test has failures. CTest's --output-on-failure will display that stderr output.

#include <catch2/catch_test_macros.hpp>
#include <catch2/reporters/catch_reporter_event_listener.hpp>
#include <catch2/reporters/catch_reporter_registrars.hpp>

#include <iostream>
#include <mutex>
#include <sstream>
#include <string>
#include <vector>

std::mutex g_failureInfoMutex;
std::vector<std::string> g_failureInfo;

#define FAIL_INFO(expr)                                      \
    do {                                                     \
        std::ostringstream oss;                              \
        oss << expr;                                         \
        std::lock_guard<std::mutex> lock(g_failureInfoMutex); \
        g_failureInfo.push_back(oss.str());                  \
    } while (false)

class FailureInfoListener : public Catch::EventListenerBase {
public:
    using EventListenerBase::EventListenerBase;

    void testCaseStarting(Catch::TestCaseInfo const&) override {
        std::lock_guard<std::mutex> lock(g_failureInfoMutex);
        g_failureInfo.clear();
    }

    void testCaseEnded(Catch::TestCaseStats const& stats) override {
        if (stats.totals.assertions.allOk()) {
            return;
        }

        std::cerr << "Additional failure information:\n";

        std::lock_guard<std::mutex> lock(g_failureInfoMutex);
        for (auto const& line : g_failureInfo) {
            std::cerr << line << '\n';
        }
    }
};

CATCH_REGISTER_LISTENER(FailureInfoListener)

Use it in tests like:

TEST_CASE("GPU test") {
    FAIL_INFO("GPU: " << gpuName);
    REQUIRE(false);
}

Run with:

ctest --output-on-failure

Catch2 does not provide a way to retrieve the listener instance from the registry, so the listener should read the shared global. Use a mutex if diagnostics can be recorded from multiple threads. A custom reporter is another option, but an event listener is the simpler recommended approach.

GitHub Issue #3183
Troubleshooting
How do I preserve a trailing space in Catch2 catch_discover_tests TEST_PREFIX?

In Catch2 v2.13.4 with CMake v3.10.3, the trailing space is lost when TEST_PREFIX is passed through add_custom_command(). Edit the Catch.cmake used by your build (usually contrib/Catch.cmake, around line 160) and replace:

-D "TEST_PREFIX=${_TEST_PREFIX}"

with:

-D "TEST_PREFIX='${_TEST_PREFIX}'"

An equivalent form is:

-D TEST_PREFIX='${_TEST_PREFIX}'

Keep VERBATIM on the add_custom_command() call. Reconfigure and rebuild so the test discovery script regenerates:

cmake -S . -B build
cmake --build build
ctest --test-dir build -N

With this change, TEST_PREFIX "${TARGET} " produces CTest names such as <target> <test name> instead of <target><test name>. If you cannot patch Catch.cmake, use a non-space separator such as ${TARGET}. or ${TARGET}: as a temporary workaround.

GitHub Issue #2149
Troubleshooting
How to fix Catch2 build failure with Clang 20: '-Wunreachable-code-return' and 'no matching function for call to get_wrapper'?

Upgrade Catch2 to v3.9.1 or newer, which includes the Clang 20 build fixes. For a Git checkout, run:

git fetch --tags
git checkout v3.9.1
CXX=clang++ cmake -S . -B build -DCMAKE_BUILD_TYPE=Release
cmake --build build

If you only need the Catch2 library and not its self-tests, disable the development build as a workaround:

CXX=clang++ cmake -S . -B build -DCATCH_DEVELOPMENT_BUILD=OFF
cmake --build build

The failures occur in the development/self-test targets, so building with CATCH_DEVELOPMENT_BUILD=OFF avoids compiling those failing test files. Using -Wno-error=unreachable-code-return only suppresses the first warning and does not resolve the get_wrapper template error.

GitHub Issue #2991
Troubleshooting
How to fix Catch2 "no matching function for call to 'get_wrapper'" with TEMPLATE_PRODUCT_TEST_CASE on macOS or Alpine?

This is caused by Clang 20/21 with libc++, not by your test syntax. Clang rejects TEMPLATE_PRODUCT_TEST_CASE with type lists of differing arities; Clang 22 fixes the compiler issue, and Catch2 PR #3173 adds a workaround.

Fix by upgrading Catch2 from 3.15.0 to a newer v3.x release containing PR #3173, or to the latest v3.x version. For a Meson subproject, update subprojects/catch2.wrap and run:

meson subprojects update catch2
meson setup --reconfigure build

For CMake FetchContent, update GIT_TAG to the latest Catch2 v3.x release and reconfigure.

Alternative workarounds:
- Upgrade the compiler to Clang 22.
- If you cannot upgrade Catch2 immediately, cherry-pick or backport the changes from catchorg/Catch2 PR #3173.

GitHub Issue #3115