Search code examples
c++googletest

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


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.


Solution

  • 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.