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

问题描述

我在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抛出,则可能会被第二次调用。但是一旦函数成功退出,就是这样。