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

Time:02-16

Using the googletest framework I want to write my own main function. Basically some custom initialization step needs to happen before RUN_ALL_TESTS is called. I'd like to skip this step, if the command line parameters for googletest indicate, no tests should be run (e.g. if --gtest_list_tests is passed).

Is it possible to retrieve this kind of information from the test framework without the need to parse the parameters myself?

What I'd like to accomplish:

#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();
}

Is this even possible? I've tried to identify members of ::testing::UnitTest, that would allow me to retrieve this kind of information, without any success so far though.

Am I going at this the wrong way? Preferrably I'd like to avoid lazily doing the initialization via fixture or similar logic requiring me to adjust every test case.

CodePudding user response:

There are various flags that might prevent google test from running any tests. I can think of at least the following:

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

You can test these cases by:

  • The first can be checked using ::testing::GTEST_FLAG(list_tests). See here.

  • The second can be tested using ::testing::GTEST_FLAG(repeat).

  • The third can be checked by reading the global variable g_help_flag. While practical, this is not ideal because it's in the internal namespace and might change in future releases.

Another alternative is to parse the command line arguments yourself.

So assuming you want to be practical, one way to get to what you want is this:


// 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();
}

Live example: https://godbolt.org/z/P36fde11T

CodePudding user response:

command line arguments are detected using the GTEST_FLAG macro. An example of what you're trying to do might look like:

#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();
}

When compiled and linked appropriately, it can be run as:

$ ./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

i.e. you don't see the Boop Boop, Beep Beep as the function was not called.

Now if you have something that you want to have run once, if you're running tests, then adding it to the testing::Environment would also do the trick:

#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();
}

When executed, it will also cope with filters (the previous example would not be able to cope in that case):

$ ./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

Again, not that the Env Beep Beep does not appear if you don't run any tests (you can check with a filter like --gtest_filter=equality, and you won't see the Env output in that case.

  • Related