MiniTest: A Lightweight C++ Unit Testing Framework

MiniTest: A Lightweight C++ Unit Testing FrameworkClick the blue text to follow immediatelyMiniTest: A Lightweight C++ Unit Testing Framework

Introduction

MiniTest is a lightweight C++ unit testing framework that provides assertion testing, parameterized testing, grouped testing, performance testing, and Mock (mock objects), suitable for the unit testing needs of small projects.

Features of this framework:

MiniTest: A Lightweight C++ Unit Testing Framework

  • Lightweight: No third-party dependencies, suitable for embedded systems, CLI tools, etc.

  • Easy to extend: Modular design, supports custom tests.

  • Supports parameterized testing: Use TEST_P to run multiple sets of input tests.

  • Supports performance testing:

    Benchmarking with BENCHMARK_FUNC to measure function execution time.

  • Supports Mock: Easily mock dependencies with Mock::SetReturn.

Project Structure

MiniTest/│── include/                 # Header files directory│   ├── TestAssert.hpp       # Assertion macros│   ├── TestFramework.hpp    # Basic testing framework│   ├── TestParams.hpp       # Parameterized testing│   ├── TestSuite.hpp        # Grouped testing│   ├── TestBenchmark.hpp    # Performance testing│   ├── TestMock.hpp         # Mock objects│── tests/                   # Test cases│── CMakeLists.txt           # CMake build script│── main.cpp                 # Main test entry│── README.md                # Project documentation

Environment Configuration

This project uses C++20 and is built with CMake.

cmake_minimum_required(VERSION 3.30)project(MiniTest)set(CMAKE_CXX_STANDARD 20)include_directories(include)add_executable(MiniTest main.cpp)target_compile_options(MiniTest PRIVATE -finput-charset=UTF-8 -fexec-charset=UTF-8)

Compile and Run

mkdir buildcd buildcmake ..make

01

Assertion Testing

Example Code

TEST(TestBoolean) {    ASSERT_TRUE(true);}TEST(TestFailure) {    ASSERT_TRUE(false); // This test will fail}TEST(TestException) {    ASSERT_THROW(throw std::runtime_error("error"), std::runtime_error);}TEST(TestSubtraction) {    ASSERT_EQ(5 - 3, 2);}

Complete Code

/*** ================================================== *  @file TestAssert.hpp *  @brief Assertion macro definitions, providing basic unit testing assertion functionality *  @author mrDarker *  @date 2025/03/18 *  @version 1.0 *  @copyright Copyright (c) 2025 mrDarker. All Rights Reserved. * ================================================== */#ifndef TEST_ASSERT_HPP#define TEST_ASSERT_HPP#include <iostream>#include <stdexcept>// Log when assertion fails#define ASSERT_FAIL(message) \\do { \\    /**std::ostringstream oss; \\    oss << "Assertion failed: " << message << " at " << __FILE__ << ":" << __LINE__; \\    std::cerr << "[ASSERT FAIL] " << oss.str() << std::endl; \\    TestLogger logger("AssertFailures"); \\    logger.LogMessage(oss.str()); \\    std::cout.flush(); \\    std::cerr.flush(); \\    throw std::runtime_error(oss.str()); \\ **/ \\} while (0)// Assertion: Check if true#define ASSERT_TRUE(condition) \\do { \\    if (!(condition)) { \\        ASSERT_FAIL(#condition " is false"); \\    } \\} while (0)// Assertion: Check if false#define ASSERT_FALSE(condition) \\do { \\    if ((condition)) { \\        ASSERT_FAIL(#condition " is true"); \\    } \\} while (0)// Assertion: Check if two values are equal#define ASSERT_EQ(expected, actual) \\do { \\    if ((expected) != (actual)) { \\        std::ostringstream oss; \\        oss << #expected " != " #actual " (" << expected << " != " << actual << ")"; \\        ASSERT_FAIL(oss.str()); \\    } \\} while (0)// Assertion: Check if two values are not equal#define ASSERT_NE(expected, actual) \\do { \\    if ((expected) == (actual)) { \\        std::ostringstream oss; \\        oss << #expected " == " #actual " (" << expected << " == " << actual << ")"; \\        ASSERT_FAIL(oss.str()); \\    } \\} while (0)// Assertion: Check if a statement throws a specified exception#define ASSERT_THROW(statement, exception_type) \\do { \\    bool caught = false; \\    try { \\        statement; \\    } catch (const exception_type&) { \\        caught = true; \\    } catch (...) { \\        ASSERT_FAIL("Unexpected exception type thrown"); \\    } \\    if (!caught) { \\        ASSERT_FAIL("Expected exception of type " #exception_type " not thrown"); \\    } \\} while (0)#endif // TEST_ASSERT_HPP

Supported Assertion Macros

MiniTest: A Lightweight C++ Unit Testing Framework

How It Works

1. ASSERT_* macros check the result of the expression.

2. If the assertion fails, it throws a std::runtime_error, causing the test to fail.

3. TestFramework::RunAllTests() is responsible for running all registered tests.

02

Parameterized Testing

Example Code

std::vector<std::tuple<int, int, int>> additionParams = {    {1, 2, 3}, {4, 5, 9}, {3, 7, 10}, {6, -2, 4}, {8, 3, 12}};TEST_P(TestParamsAddition, additionParams, int a, int b, int expected) {    ASSERT_EQ(a + b, expected);}

Complete Code

/** * ================================================== *  @file TestParams.hpp *  @brief Parameterized testing framework, supports data-driven testing *  @author mrDarker *  @date 2025/03/18 *  @version 1.1 *  @copyright Copyright (c) 2025 mrDarker. All Rights Reserved. * ================================================== */#ifndef TEST_PARAMS_HPP#define TEST_PARAMS_HPP#include <vector>#include <string>#include <functional>#include <iostream>#include <sstream>#include <tuple>#include "TestLogger.hpp"// Storage structure for parameterized testsclass TestParams {public:    // Register parameterized test    template <typename Func, typename... Args>    static void RegisterParamTest(const std::string& name, Func func, const std::vector<std::tuple<Args...>>& params) {        for (const auto& paramSet : params) {            std::ostringstream oss;            oss << name << FormatParams(paramSet);            GetParamTests().push_back({oss.str(), [func, paramSet]() { std::apply(func, paramSet); }});        }    }    // Run all parameterized tests    static void RunAllParamTests() {        TestLogger logger("ParamTests");        int passed = 0, failed = 0;        for (const auto&[name, func] : GetParamTests()) {            std::cout.flush();            std::cerr.flush();            std::cout << "[RUNNING] " << name << std::endl;            try {                func();  // No-parameter call                std::cout << "[PASS] " << name << std::endl;                logger.LogTestResult(name, true);                ++passed;            } catch (const std::exception& ex) {                std::cerr << "[FAIL] " << name << " - " << ex.what() << std::endl;                logger.LogTestResult(name, false);                ++failed;            }        }        // Print test statistics        std::cout << "===========================================" << std::endl;        std::cout << "Total: " << (passed + failed) << ", Passed: " << passed << ", Failed: " << failed << std::endl;        std::cout << "===========================================" << std::endl;        std::cout.flush();        std::cerr.flush();    }private:    struct ParamTestCase {        std::string name;        std::function<void()> func;    };    static std::vector<ParamTestCase>& GetParamTests() {        static std::vector<ParamTestCase> paramTests;        return paramTests;    }    // Format parameter list    template <typename Tuple, size_t... Index>    static std::string FormatTupleImpl(const Tuple& tuple, std::index_sequence<Index...>) {        std::ostringstream oss;        ((oss << (Index == 0 ? "" : ", ") << std::get<Index>(tuple)), ...);        return "(" + oss.str() + ")";    }    template <typename... Args>    static std::string FormatParams(const std::tuple<Args...>& params) {        return FormatTupleImpl(params, std::index_sequence_for<Args...>{});    }}; // Parameterized test macro#define TEST_P(test_name, param_data, ...) \\void test_name(__VA_ARGS__); \\namespace { \\    struct Register_##test_name { \\        Register_##test_name() { \\            static const auto _param_data = param_data; \\            TestParams::RegisterParamTest(#test_name, test_name, _param_data); \\        } \\    }; \\    static Register_##test_name g_register_##test_name; \\} \\void test_name(__VA_ARGS__)#endif // TEST_PARAMS_HPP

How It Works

1. TEST_P macro automatically generates test functions and registers them with TestParams::RegisterParamTest.

2. std::tuple<> stores different test data.

3. TestParams::RunAllParamTests() sequentially calls test cases and executes them with different parameters.

03

Grouped Testing

Example Code

TEST_SUITE(MathTests, TestSuiteAddition) {    ASSERT_EQ(2 + 3, 5);}TEST_SUITE_F(MySuiteTestFixture, MathTests, TestAddition) {    ASSERT_EQ(1 + 1, 2);}

Complete Code

/** * ================================================== *  @file TestSuite.hpp *  @brief Test suite management, supports running specified test suites *  @author mrDarker *  @date 2025/03/18 *  @version 1.1 *  @copyright Copyright (c) 2025 mrDarker. All Rights Reserved. * ================================================== */#ifndef TEST_SUITE_HPP#define TEST_SUITE_HPP#include &lt;vector&gt;#include &lt;functional&gt;#include &lt;unordered_map&gt;#include &lt;iostream&gt;#include &lt;ranges&gt;#include &lt;thread&gt;#include "TestLogger.hpp"class TestSuite {public:    // Structure: Test case    struct TestCase {        std::string name;           // Test name        std::function&lt;void()&gt; func; // Test execution function    };    /**     * @brief Register test to specified Suite     * @param suite Test suite name     * @param test Test name     * @param func Test function     */    static void RegisterTest(const std::string&amp; suite, const std::string&amp; test, const std::function&lt;void()&gt; &amp;func) {        GetSuites()[suite].push_back({test, func});    }    /**     * @brief Print all registered test suites     */    static void ListSuites() {        std::cout &lt;&lt; "[AVAILABLE TEST SUITES]" &lt;&lt; std::endl;        for (const auto &amp;suite: GetSuites() | std::views::keys) {            std::cout &lt;&lt; "- " &lt;&lt; suite &lt;&lt; std::endl;        }    }    /**     * @brief Execute Setup for specified test suite     */    static void SetupSuite(const std::string&amp; suite) {        if (auto&amp; setupFuncs = GetSetupFuncs(); setupFuncs.contains(suite)) setupFuncs[suite]();    }    /**     * @brief Execute Teardown for specified test suite     */    static void TeardownSuite(const std::string&amp; suite) {        if (auto&amp; teardownFuncs = GetTeardownFuncs(); teardownFuncs.contains(suite)) teardownFuncs[suite]();    }    /**     * @brief Get all test suite's Setup function mapping     * @return std::unordered_map&lt;std::string, std::function&lt;void()&gt;&gt;&amp;     */    static std::unordered_map&lt;std::string, std::function&lt;void()&gt;&gt;&amp; GetSetupFuncs() {        static std::unordered_map&lt;std::string, std::function&lt;void()&gt;&gt; setupFuncs;        return setupFuncs;    }    /**     * @brief Get all test suite's Teardown function mapping     * @return std::unordered_map&lt;std::string, std::function&lt;void()&gt;&gt;&amp;     */    static std::unordered_map&lt;std::string, std::function&lt;void()&gt;&gt;&amp; GetTeardownFuncs() {        static std::unordered_map&lt;std::string, std::function&lt;void()&gt;&gt; teardownFuncs;        return teardownFuncs;    }    /**     * @brief Run specified test suite, optional filter for single test     * @param suite Test suite name     * @param testFilter Specific test to execute (default is empty, execute entire suite)     */    static void RunSuite(const std::string&amp; suite, const std::string&amp; testFilter = "") {        auto&amp; suites = GetSuites();        if (!suites.contains(suite)) {            std::cerr &lt;&lt; "[ERROR] Test suite '" &lt;&lt; suite &lt;&lt; "' not found.\n";            return;        }        auto&amp; tests = suites[suite];        // If testFilter is empty, execute entire Suite        if (testFilter.empty()) {            std::cout &lt;&lt; "[RUNNING SUITE] " &lt;&lt; suite &lt;&lt; std::endl;            RunTests(tests, suite);            return;        }        // Check if the Test exists        auto it = std::ranges::find_if(tests, [&amp;](const TestCase&amp; test) {            return test.name == testFilter;        });        // If it exists, execute that Test        if (it != tests.end()) {            std::cout &lt;&lt; "[RUNNING SINGLE TEST] " &lt;&lt; suite &lt;&lt; "::" &lt;&lt; testFilter &lt;&lt; std::endl;            RunTests({*it}, suite);        } else {            std::cerr &lt;&lt; "[ERROR] Test '" &lt;&lt; testFilter &lt;&lt; "' not found in suite '" &lt;&lt; suite &lt;&lt; "'.\n";        }    }    /**     * @brief Run list of tests     * @param tests List of tests to execute     * @param suite Name of the test suite     */    static void RunTests(const std::vector&lt;TestCase&gt;&amp; tests, const std::string&amp; suite) {        TestLogger logger(suite);        int passed = 0, failed = 0;        // Execute Setup        SetupSuite(suite);        for (const auto&amp; [name, func] : tests) {            std::cout &lt;&lt; "[RUNNING] " &lt;&lt; name &lt;&lt; std::endl;            try {                func();                std::cout &lt;&lt; "[PASS] " &lt;&lt; name &lt;&lt; std::endl;                logger.LogTestResult(name, true);                ++passed;            } catch (const std::exception&amp; ex) {                std::cerr &lt;&lt; "[FAIL] " &lt;&lt; name &lt;&lt; " - " &lt;&lt; ex.what() &lt;&lt; std::endl;                logger.LogTestResult(name, false);                ++failed;            }        }        // Execute Teardown        TeardownSuite(suite);        std::cout &lt;&lt; "[SUITE] " &lt;&lt; suite &lt;&lt; " - Passed: " &lt;&lt; passed &lt;&lt; ", Failed: " &lt;&lt; failed &lt;&lt; std::endl;    }    /**    * @brief Run all test suites    */    static void RunAllSuites() {        std::vector&lt;std::thread&gt; threads;        for (const auto &amp;key: GetSuites() | std::views::keys) {            threads.emplace_back([key]() { RunSuite(key); });        }        for (auto&amp; t : threads) {            if (t.joinable()) t.join();        }    }private:    /**    * @brief Get all registered test suites    */    static std::unordered_map&lt;std::string, std::vector&lt;TestCase&gt;&gt;&amp; GetSuites() {        static std::unordered_map&lt;std::string, std::vector&lt;TestCase&gt;&gt; suites;        return suites;    }}; // **Register Setup**#define TEST_SUITE_SETUP(suite_name, func) \\namespace { struct RegisterSetup_##suite_name { \\    RegisterSetup_##suite_name() { TestSuite::GetSetupFuncs()[#suite_name] = func; } \\}; static RegisterSetup_##suite_name g_registerSetup_##suite_name; } // **Register Teardown**#define TEST_SUITE_TEARDOWN(suite_name, func) \\namespace { struct RegisterTeardown_##suite_name { \\    RegisterTeardown_##suite_name() { TestSuite::GetTeardownFuncs()[#suite_name] = func; } \\}; static RegisterTeardown_##suite_name g_registerTeardown_##suite_name; } // **Register Normal Test**#define TEST_SUITE(suite_name, test_name) \\void test_name(); \\namespace { \\    struct Register_##test_name { \\        Register_##test_name() { TestSuite::RegisterTest(#suite_name, #test_name, test_name); } \\    }; \\    static Register_##test_name g_register_##test_name; } \\void test_name() // **Register Test with Fixture**#define TEST_SUITE_F(fixture_name, suite_name, test_name) \\class test_name : public fixture_name { \\public: \\    void Run(); \\}; \\namespace { \\    struct Register_##test_name { \\        Register_##test_name() { \\            TestSuite::RegisterTest(#suite_name, test_name, []() { \\                test_name instance; \\                instance.Run(); \\            }); \\        } \\    }; \\    static Register_##test_name g_register_##test_name; } \\void test_name::Run()#endif // TEST_SUITE_HPP

How It Works

1. TEST_SUITE(suite, test) registers tests with TestSuite::RegisterTest.

2. TEST_SUITE_F(fixture, suite, test) supports using SetUp() and TearDown().

3. TestSuite::RunSuite(“MathTests”) runs the entire test suite.

04

Performance Testing

Example Code

BENCHMARK_FUNC(MyTestFunction, 5);void MyTestFunction() {    std::vector&lt;int&gt; data(100000);    std::ranges::generate(data.begin(), data.end(), rand);    std::ranges::sort(data.begin(), data.end());}

Complete Code

/** * ================================================== *  @file TestBenchmark.hpp *  @brief Benchmark testing framework, supports multiple runs, average time statistics, and parameterized benchmarks *  @author mrDarker *  @date 2025/03/18 *  @version 1.2 *  @copyright Copyright (c) 2025 mrDarker. All Rights Reserved. * ================================================== */#ifndef TEST_BENCHMARK_HPP#define TEST_BENCHMARK_HPP#include &lt;chrono&gt;#include &lt;functional&gt;#include &lt;iostream&gt;#include &lt;vector&gt;#include &lt;unordered_map&gt;#include "TestLogger.hpp"class TestBenchmark {public:    // Normal benchmark test (no parameters)    static void RegisterBenchmark(const std::string&amp; name, const std::function&lt;void()&gt;&amp; func, const int iterations) {        GetBenchmarks()[name] = {func, iterations};    }    // Parameterized benchmark test (with parameters)    template &lt;typename Func, typename... Args&gt;    static void RegisterBenchmark(const std::string&amp; name, Func func, int iterations, Args... args) {        auto wrapper = [func, args...]() { func(args...); };        GetBenchmarks()[name] = {wrapper, iterations};    }    // Run all benchmark tests    static void RunAllBenchmarks() {        RunFilteredBenchmarks([](const std::string&amp;) { return true; }, "AllBenchmarks");    }    // Run specified benchmark test    static void RunBenchmark(const std::string&amp; name) {        RunFilteredBenchmarks([name](const std::string&amp; testName) {            return testName == name;        }, "Benchmark_" + name);    }    // Test the average execution time of a specific function    template &lt;typename ReturnType, typename... Args&gt;    static void BenchmarkFunction(const std::string&amp; name, ReturnType (*func)(Args...), const int iterations, Args... args) {        std::cout &lt;&lt; "[BENCHMARK] Running " &lt;&lt; name &lt;&lt; " for " &lt;&lt; iterations &lt;&lt; " iterations..." &lt;&lt; std::endl;        std::vector&lt;double&gt; times;        for (int i = 0; i &lt; iterations; ++i) {            std::cout.flush();            std::cerr.flush();            auto start = std::chrono::high_resolution_clock::now();            if constexpr (sizeof...(Args) &gt; 0) {                func(args...);  // Call function with parameters if there are any            } else {                func();         // Call function without parameters if there are none            }            auto end = std::chrono::high_resolution_clock::now();            std::chrono::duration&lt;double, std::milli&gt; duration = end - start;            times.push_back(duration.count());        }        double totalTime = 0;        for (const double t : times) totalTime += t;        const double avgTime = totalTime / iterations;        std::cout &lt;&lt; "[BENCHMARK] " &lt;&lt; name &lt;&lt; " Avg Time: " &lt;&lt; avgTime &lt;&lt; " ms" &lt;&lt; std::endl;    }private:    struct BenchmarkCase {        std::function&lt;void()&gt; func;        int iterations{};    };    static std::unordered_map&lt;std::string, BenchmarkCase&gt;&amp; GetBenchmarks() {        static std::unordered_map&lt;std::string, BenchmarkCase&gt; benchmarks;        return benchmarks;    }    // General performance test execution    static void RunFilteredBenchmarks(const std::function&lt;bool(const std::string&amp;)&gt;&amp; filter, const std::string&amp; logCategory) {        TestLogger logger(logCategory);        for (const auto&amp; [fst, snd] : GetBenchmarks()) {            if (!filter(fst)) continue;            const auto&amp; [func, iterations] = snd;            std::cout &lt;&lt; "[BENCHMARK] Running " &lt;&lt; fst &lt;&lt; " for " &lt;&lt; iterations &lt;&lt; " iterations..." &lt;&lt; std::endl;            std::vector&lt;double&gt; times;            for (int i = 0; i &lt; iterations; ++i) {                std::cout.flush();                std::cerr.flush();                auto start = std::chrono::high_resolution_clock::now();                func();                auto end = std::chrono::high_resolution_clock::now();                std::chrono::duration&lt;double, std::milli&gt; duration = end - start;                times.push_back(duration.count());            }            double totalTime = 0;            for (const double t : times) totalTime += t;            const double avgTime = totalTime / iterations;            std::cout &lt;&lt; "[BENCHMARK] " &lt;&lt; fst &lt;&lt; " Avg Time: " &lt;&lt; avgTime &lt;&lt; " ms" &lt;&lt; std::endl;            logger.LogMessage("[BENCHMARK] " + fst + " Avg Time: " + std::to_string(avgTime) + " ms");        }    }}; // Normal benchmark test (no parameters)#define BENCHMARK(test_name, iterations) \\void test_name(); \\namespace { \\    struct Register_##test_name { \\        Register_##test_name() { \\            TestBenchmark::RegisterBenchmark(#test_name, test_name, iterations); \\        } \\    }; \\    static Register_##test_name g_register_##test_name; } \\void test_name() // Specify function benchmark test#define BENCHMARK_FUNC(func, iterations, ...) \\namespace { \\    struct Register_##func { \\        Register_##func() { \\            TestBenchmark::BenchmarkFunction(#func, func, iterations, ##__VA_ARGS__); \\        } \\    }; \\    static Register_##func g_register_##func; }#endif // TEST_BENCHMARK_HPP

How It Works

1. BENCHMARK_FUNC registers MyTestFunction and runs it 5 times.

2. TestBenchmark::BenchmarkFunction() calculates the average execution time.

05

Mock Objects

Example Code

MOCK_METHOD(int, GetRandomNumber, ());TEST(TestMockExample) {    Mock::SetReturn(GetRandomNumber, 42);    ASSERT_EQ(GetRandomNumber(), 42);}

Complete Code

/** * ================================================== *  @file TestMock.hpp *  @brief Mock object framework, supports Mock method and return value setting *  @author mrDarker *  @date 2025/03/18 *  @version 1.0 *  @copyright Copyright (c) 2025 mrDarker. All Rights Reserved. * ================================================== */#ifndef TEST_MOCK_HPP#define TEST_MOCK_HPP#include &lt;unordered_map&gt;#include &lt;functional&gt;#include &lt;typeindex&gt;#include &lt;map&gt;class Mock {public:    // Set return value for Mock method    template &lt;typename ReturnType&gt;    static void SetReturn(ReturnType (*func)(), ReturnType returnValue) {        auto wrapper = [returnValue]() -&gt; ReturnType { return returnValue; };        GetMockFunctions&lt;ReturnType&gt;()[reinterpret_cast&lt;void*&gt;(func)] = wrapper;    }    // Call Mock method    template &lt;typename ReturnType&gt;    static ReturnType Invoke(ReturnType (*func)()) {        auto&amp; mockMap = GetMockFunctions&lt;ReturnType&gt;();        auto it = mockMap.find(reinterpret_cast&lt;void*&gt;(func));        if (it != mockMap.end()) {            return it-&gt;second();        }        // std::cerr &lt;&lt; "[MOCK ERROR] Function '" &lt;&lt; typeid(func).name() &lt;&lt; "' not mocked!\n";        return ReturnType();  // Default return 0 / empty value    }    // Clear Mock    template &lt;typename ReturnType&gt;    static void Reset() {        GetMockFunctions&lt;ReturnType&gt;().clear();    }    // Clear all Mock methods    static void ResetAll() {        mockStorage().clear();    }private:    // Store different types of Mock methods    template &lt;typename ReturnType&gt;    static std::unordered_map&lt;void*, std::function&lt;ReturnType()&gt;&gt;&amp; GetMockFunctions() {        static std::unordered_map&lt;void*, std::function&lt;ReturnType()&gt;&gt; mockFunctions;        return mockFunctions;    }    static std::map&lt;std::type_index, void*&gt;&amp; mockStorage() {        static std::map&lt;std::type_index, void*&gt; storage;        return storage;    }}; // MOCK_METHOD macro#define MOCK_METHOD(returnType, functionName, params) \\    returnType functionName params; \\    namespace { \\        struct RegisterMock_##functionName { \\            RegisterMock_##functionName() { \\                Mock::SetReturn(functionName, returnType()); \\            } \\        }; \\        static RegisterMock_##functionName g_register_mock_##functionName; \\    } \\    returnType functionName params { return Mock::Invoke(functionName); }#endif // TEST_MOCK_HPP

How It Works

1. MOCK_METHOD defines a Mock method.

2. Mock::SetReturn(func, value) sets the return value.

3. Mock::Reset() clears the Mock method.

06

Run Tests

int main() {    TestFramework::RunAllTests();    TestParams::RunAllParamTests();    TestBenchmark::RunAllBenchmarks();    TestSuite::RunAllSuites();    return 0;}

Conclusion

MiniTest provides assertions, parameterized, grouped, performance testing, and Mock, suitable for unit testing in small C++ projects.

✅ Lightweight, no third-party dependencies✅ Supports parameterized testing✅ Supports performance testing✅ Supports Mock✅ Easy to extend

END

MiniTest: A Lightweight C++ Unit Testing Framework

Link:

https://blog.csdn.net/m0_58648890/article/details/146364148

This article is reprinted with permission from 51Testing. The text contained in the reprinted article comes from the author. If there are any issues regarding content or copyright, please contact 51Testing for deletion.

MiniTest: A Lightweight C++ Unit Testing FrameworkLike and ShareMiniTest: A Lightweight C++ Unit Testing FrameworkShareMiniTest: A Lightweight C++ Unit Testing FrameworkView

Leave a Comment