在运行时检测 Catch2 中的特定标签匹配

Detect specific tag match in Catch2 at runtime

我在我的 Catch2 项目中进行了集成测试,该测试依赖于正在设置的一些昂贵的全局状态。我只想在测试运行器实际测试依赖它的系统时才初始化该全局状态。

我所看到的工作,但它有点可怕......它取决于 Catch 配置中相当多的实现细节。

这是我的主要内容:

#define CATCH_CONFIG_RUNNER
#include "catch.hpp"
...

int main(int argc, const char* argv[])
{
    // Construct a fake TestCaseInfo to match against the [integration] tag
    const char * expensive_tag = "integration";
    Catch::SourceLineInfo fake_source_line("?", 0)
    Catch::TestCaseInfo fake_test_case("?", "?", "?", {expensive_tag}, fake_source_line);

    Catch::Session session;
    session.applyCommandLine(argc, argv);
    auto test_spec = session.config().testSpec();
    const bool want_integration_tests = test_spec.matches(fake_test_spec);

    if(want_integration_tests)
    {
        do_expensive_setup();
    }
    
    return session.run();
}

然后我的测试文件就是:

#include "catch.hpp"
...

TEST_CASE("expensive-to-initialize system", "[.integration]")
{
    REQUIRE(expensive_setup_is_done());

    SECTION("has property 1") { ... }
    SECTION("has property 2") { ... }
    ...
}

请注意,因为有多个部分(在我的实际项目中,有多个测试用例)依赖于全局设置,所以我不能只将初始化移到 TEST_CASE 的顶部。

有没有更好的方法?

只需按需进行初始化,使用 std::call_once:

TEST_CASE("expensive-to-initialize system", "[.integration]")
{
    static std::once_flag init_flag;
    std::call_once(init_flag, do_expensive_setup);
    
    // ...
}

这将确保 do_expensive_setup 仅在需要时被调用一次。如果有多个地方需要这个设置,只需将其包装在一个函数中即可。

请注意,如果 do_expensive_setup 抛出,它可能会被调用第二次。但是一旦函数成功退出,就是这样。