1

我的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.

有没有更好的办法?

4

1 回答 1

3

只需按需进行初始化,使用类似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抛出,它可能会被第二次调用。但是一旦函数成功退出,就是这样。

于 2020-08-28T01:38:08.977 回答