有没有办法检测命令行参数而不是 运行 测试?

Is there a way to detect command line arguments not running tests?

我想使用 googletest 框架编写自己的 main 函数。基本上,在调用 RUN_ALL_TESTS 之前需要进行一些自定义初始化步骤。我想跳过这一步,如果 googletest 的命令行参数指示,则不应进行任何测试 运行(例如,如果 --gtest_list_tests 已通过)。

是否可以在不需要自己解析参数的情况下从测试框架中获取此类信息?

我想完成的事情:

#include <gtest/gtest.h>

bool RunAllTestsDoesNotRunTests()
{
    // should return false, if and only if RUN_ALL_TESTS() runs any test cases

    // implementation?
}

int main(int argc, char** argv) {
    testing::InitGoogleTest(&argc, argv);

    if (!RunAllTestsDoesNotRunTests())
    {
        DoExpensiveInitialization();
    }

    return RUN_ALL_TESTS();
}

这可能吗?我试图识别 ::testing::UnitTest 的成员,这将允许我检索此类信息,但到目前为止没有任何成功。

我是不是走错了路?我最好避免通过固定装置或类似逻辑懒惰地进行初始化,要求我调整每个测试用例。

使用 GTEST_FLAG 宏检测命令行参数。您尝试执行的操作的示例可能如下所示:

#include <gtest/gtest.h>

TEST(equality, always_passes) {
    EXPECT_TRUE(true);
}

bool RunAllTestsDoesNotRunTests()
{
    return ::testing::GTEST_FLAG(list_tests);
}

void DoExpensiveInitialization() {
    std::cout << "Boop Boop, Beep Beep" << std::endl;
}

int main(int argc, char** argv) {
    testing::InitGoogleTest(&argc, argv);

    if (!RunAllTestsDoesNotRunTests())
    {
        DoExpensiveInitialization();
    }

    return RUN_ALL_TESTS();
}

适当编译和链接后,可以运行为:

$ ./a.out
Boop Boop, Beep Beep
[==========] Running 1 test from 1 test suite.
[----------] Global test environment set-up.
[----------] 1 test from equality
[ RUN      ] equality.always_passes
[       OK ] equality.always_passes (0 ms)
[----------] 1 test from equality (0 ms total)

[----------] Global test environment tear-down
[==========] 1 test from 1 test suite ran. (0 ms total)
[  PASSED  ] 1 test.
$ ./a.out --gtest_list_tests
equality.
  always_passes

即您看不到 Boop Boop, Beep Beep,因为未调用该函数。

现在,如果您想要 运行 一次,如果您正在 运行 测试,那么将它添加到 testing::Environment 也可以达到目的:

#include <gtest/gtest.h>

class MyEnvironment: public ::testing::Environment
{
public:
  virtual ~MyEnvironment() = default;

  // Override this to define how to set up the environment.
  virtual void SetUp() { std::cout << "Env Beep Beep" << std::endl; }

  // Override this to define how to tear down the environment.
  virtual void TearDown() {}
};

TEST(equality, always_passes) {
    EXPECT_TRUE(true);
}    

int main(int argc, char** argv) {
    testing::InitGoogleTest(&argc, argv);

    auto* env = new MyEnvironment();
    ::testing::AddGlobalTestEnvironment(env);

    return RUN_ALL_TESTS();
}

执行时,它也会处理过滤器(在那种情况下前面的例子将无法处理):

$ ./a.out --gtest_filter=equality\*
Note: Google Test filter = equality*
[==========] Running 1 test from 1 test suite.
[----------] Global test environment set-up.
Env Beep Beep
[----------] 1 test from equality
[ RUN      ] equality.always_passes
[       OK ] equality.always_passes (0 ms)
[----------] 1 test from equality (0 ms total)

[----------] Global test environment tear-down
[==========] 1 test from 1 test suite ran. (0 ms total)
[  PASSED  ] 1 test.
$ ./a.out --gtest_filter=equality\* --gtest_list_tests
equality.
  always_passes

同样,如果您不 运行 任何测试,Env Beep Beep 就不会出现(您可以使用 --gtest_filter=equality 之类的过滤器进行检查,但您不会看到Env 这种情况下的输出。

有各种标志可能会阻止 google 测试 运行 任何测试。我至少能想到以下几点:

  1. --gtest_list_tests通过了
  2. --gtest_repeat=0通过了
  3. --help or other forms of it like -h or any unrecognized flag with gtest prefix is passed See here.

您可以通过以下方式测试这些案例:

  • 第一个可以使用 ::testing::GTEST_FLAG(list_tests) 检查。参见 here

  • 第二个可以使用::testing::GTEST_FLAG(repeat)进行测试。

  • 第三个可以通过读取全局变量g_help_flag来查看。虽然实用,但这并不理想,因为它位于 internal 命名空间中,并且可能会在未来的版本中发生变化。

另一种方法是自己解析命令行参数。

因此,假设您想变得实用,获得您想要的东西的一种方法是:


// Defining g_help_flag as an extern variable
namespace testing {
  namespace internal {
    extern bool g_help_flag;
  }
}

bool RunAllTestsDoesNotRunTests()
{
    // should return false, if and only if RUN_ALL_TESTS() runs any test cases

    // implementation?
    return ( ::testing::GTEST_FLAG(list_tests) || 
        ::testing::GTEST_FLAG(repeat) == 0 ||
        ::testing::internal::g_help_flag);
}

int main(int argc, char** argv) {
    testing::InitGoogleTest(&argc, argv);

    if (!RunAllTestsDoesNotRunTests())
    {
        // DoExpensiveInitialization();
        std::cout << "Expensive initialization!" << std::endl;
    } else {
        std::cout << "No Expensive initialization!" << std::endl;
    }

    return RUN_ALL_TESTS();
}

实例:https://godbolt.org/z/P36fde11T