Обнаружение соответствия конкретного тега в Catch2 во время выполнения

#c #c 14 #catch-unit-test #catch2

#c #c 14 #catch-модульный тест #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 .

Есть ли лучший способ?

Ответ №1:

Просто выполните инициализацию по требованию, используя что-то вроде 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 выдает ошибку, она может быть вызвана во второй раз. Но как только функция успешно завершится, это все.

Комментарии:

1. Ого, не знал об std::call_once() . Это идеально!

2. будет ли static const bool dummy = do_expensive_setup(), false; также работать? Некоторым это может показаться более уродливым, но я не возражаю, поскольку я знаю о том, как работает статика.

3. @NoSenseEtAl Да, это тоже отлично работает (по модулю отсутствующих скобок).