μt¹ – небольшая (~100 Кб), header-only (единственный файл ut.hpp) C++20 библиотека модульного тестирования.
В отличие от большинства аналогов (сatch³, doctest⁴, etc.) основана не на макросах, а на возможностях стандарта C++20.
Библиотекой поддерживаются техники TDD (разработка через тестирование), BDD (разработка через поведение) и язык BDD Gherkin.
Зависит только от std.
Примеры:
#include <boost/ut.hpp> // import boost.ut;
constexpr auto sum(auto... values) { return (values + ...); }
int main() {
  using namespace boost::ut;
  "sum"_test = [] {
    expect(sum(0) == 0_i);
    expect(sum(1, 2) == 3_i);
    expect(sum(1, 2) > 0_i and 41_i == sum(40, 2));
  };
}
#include <boost/ut.hpp>
#include <chrono>
#include <iostream>
#include <string>
#include <string_view>
namespace benchmark {
struct benchmark : boost::ut::detail::test {
  explicit benchmark(std::string_view _name)
      : boost::ut::detail::test{"benchmark", _name} {}
  template <class Test>
  auto operator=(Test _test) {
    static_cast<boost::ut::detail::test&>(*this) = [&_test, this] {
      const auto start = std::chrono::high_resolution_clock::now();
      _test();
      const auto stop = std::chrono::high_resolution_clock::now();
      const auto ns =
          std::chrono::duration_cast<std::chrono::nanoseconds>(stop - start);
      std::clog << "[" << name << "] " << ns.count() << " ns\n";
    };
  }
};
[[nodiscard]] auto operator""_benchmark(const char* _name,
                                        decltype(sizeof("")) size) {
  return ::benchmark::benchmark{{_name, size}};
}
#if defined(__GNUC__) or defined(__clang__)
template <class T>
void do_not_optimize(T&& t) {
  asm volatile("" ::"m"(t) : "memory");
}
#else
#pragma optimize("", off)
template <class T>
void do_not_optimize(T&& t) {
  reinterpret_cast<char volatile&>(t) =
      reinterpret_cast<char const volatile&>(t);
}
#pragma optimize("", on)
#endif
}  // namespace benchmark
int main() {
  using namespace boost::ut;
  using namespace benchmark;
  "string creation"_benchmark = [] {
    std::string created_string{"hello"};
    do_not_optimize(created_string);
  };
}
BDD:
#include <boost/ut.hpp>
int main() {
  using namespace boost::ut::literals;
  using namespace boost::ut::operators::terse;
  using namespace boost::ut::bdd;
  "Scenario"_test = [] {
    given("I have...") = [] {
      when("I run...") = [] {
        then("I should have...") = [] { 1_u == 1u; };
        then("I should have...") = [] { 1u == 1_u; };
      };
    };
  };
  feature("Calculator") = [] {
    scenario("Addition") = [] {
      given("I have number 40") = [] {
        auto number = 40;
        when("I add 2 to number") = [&number] { number += 2; };
        then("I expect number to be 42") = [&number] { 42_i == number; };
      };
    };
  };
  // clang-format off
  scenario("Addition");
    given("I have number 40");
      auto number = 40;
    when("I add 2 to number");
      number += 2;
    then("I expect number to be 42");
      42_i == number;
}
Gherkin:
#include <boost/ut.hpp>
#include <fstream>
#include <numeric>
#include <streambuf>
#include <string>
template <class T>
class calculator {
 public:
  auto enter(const T& value) -> void { values_.push_back(value); }
  auto add() -> void {
    result_ = std::accumulate(std::cbegin(values_), std::cend(values_), T{});
  }
  auto sub() -> void {
    result_ = std::accumulate(std::cbegin(values_) + 1, std::cend(values_),
                              values_.front(), std::minus{});
  }
  auto get() const -> T { return result_; }
 private:
  std::vector<T> values_{};
  T result_{};
};
int main(int argc, const char** argv) {
  using namespace boost::ut;
  bdd::gherkin::steps steps = [](auto& steps) {
    steps.feature("Calculator") = [&] {
      steps.scenario("*") = [&] {
        steps.given("I have calculator") = [&] {
          calculator<int> calc{};
          steps.when("I enter {value}") = [&](int value) { calc.enter(value); };
          steps.when("I press add") = [&] { calc.add(); };
          steps.when("I press sub") = [&] { calc.sub(); };
          steps.then("I expect {value}") = [&](int result) {
            expect(that % calc.get() == result);
          };
        };
      };
    };
  };
  // clang-format off
  "Calculator"_test = steps |
    R"(
      Feature: Calculator
        Scenario: Addition
          Given I have calculator
           When I enter 40
           When I enter 2
           When I press add
           Then I expect 42
        Scenario: Subtraction
          Given I have calculator
           When I enter 4
           When I enter 2
           When I press sub
           Then I expect 2
    )";
  // clang-format on
  if (argc == 2) {
    const auto file = [](const auto path) {
      std::ifstream file{path};
      return std::string{(std::istreambuf_iterator<char>(file)),
                         std::istreambuf_iterator<char>()};
    };
    "Calculator"_test = steps | file(argv[1]);
  }
}
- https://github.com/boost-ext/ut
 - https://boost-ext.github.io/ut – примеры, документация, бенчмарки
 - https://github.com/catchorg/Catch2
 - https://github.com/doctest/doctest
 - https://boost-ext.github.io/ut/denver-cpp-2019 – слайд-презентация.
 - https://www.youtube.com/watch?v=irdgFyxOs_Y – презентация на CppCon 2020.
 


