How can I use Google Test to call specific test functions at specific places in the main() function?

StackOverflow https://stackoverflow.com/questions/21310067

Question

I am using TDD and Google Test for a project that involves numerical simulations. The state of the data gets changed within a loop in the main function, but there are requirements that need to be fulfilled after each change. If all requirements are fulfilled for a test case, the acceptance test passed:

while(simulation)
     modify simulation data
     FIRST_TEST()
     some other simulation operations
     SECOND_TEST()

The GTest primer states that usually RUN_ALL_TESTS() is called. The Advanced Guide shows how to run sub-tests, by filtering out tests from RUN_ALL_TESTS. However, I would like to know how to invoke tests individually.

Otherwise I would need to write a new acceptance testing application each time I need a new test like FIRST_ and SECOND_ in the pseudocode snippet above.

Some more background: I’m using the OpenFOAM framework for Computational Fluid Dynamics, so creating global fixtures outside of main is not an option. The simulation application requires a directory and configuration files to run, and the global objects in main are correlated (require each other for initialization). One example of such an application is OpenFOAM-2.2.x.

Further Notes

I took the accepted answer as well as the answer on how to use argc and argv as global variables within the test found on another question on Stack Overflow and I summarized this into this compile-able small model, maybe someone finds it useful:

#include <gtest/gtest.h>
#include <iostream>

class Type 
{
    int value_ = 0;
    int times_ = 1; 

    public: 

        Type(int x) : value_(x) {}; 

        void operator()(){
            if (times_ < 10) {
                ++times_; 
                value_ *= times_; 
            }
        }

        int value () const { return value_; } 
}; 

class mySeparatedTests : public ::testing::Test 
{
    protected:

      template<typename Type>
      void TEST_ONE(Type const &t)
      {
          ASSERT_TRUE((t.value() % 2) == 0); 
      }

      template<typename Type> 
      void TEST_TWO(Type const & t)
      {
          ASSERT_TRUE((t.value() - 5) > 0); 
      }
};

TEST_F(mySeparatedTests, testName)
{
    extern char** globalArgv; 
    char** argv = globalArgv;

    // Simulation parameters and objects requiring argc and argv for initialization. 
    int simulationEndTime;  

    *argv[1] >> simulationEndTime;  

    Type typeObject(*argv[2]); 

    TEST_ONE(typeObject); 

    // Simulation loop. 
    for (int i = 0; i < simulationEndTime; ++i)
    {
        typeObject(); 

        TEST_TWO(typeObject); 
    }
}

int globalArgc; 
char** globalArgv; 

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

    globalArgc = argc; 
    globalArgv = argv; 

    return RUN_ALL_TESTS(); 

    return 0; 
}

This approach, as described in the accepted answer, ports the simulation code from main into TEST_F, and uses the mySeparatedTests class functions to define individual tests, that can then be called anywhere. This is compiled with:

g++ -std=c++11 -l gtest main.cpp  -o main

And tests fail/pass depending on parsed parameter pairs;

this fails:

./main 1 1 

this succeeds:

./main 2 2 

Note: I’m aware of char/int conversion happening; this is just to show how to pick up args.

Était-ce utile?

La solution

My guess is that you have slightly misunderstood what googletest does. The control of the test sequence is controlled by the test runner. What you could do is define a single test with your while loop with the difference that your FIRST_TEST, etc are functions of a fixture, with some assertions. For example:

instead of:

int main(...) { ... while (...) PERFORM_TEST("A"); ... }
TEST(A,some_test) {}

you could take the standard googletest runner main and define:

// fixture
class MyTest : public ::testing::Test {
protected:
  bool simulation() {
    ///...
  }

  void TEST_A() {
    ASSERT_EQ(...);
    //...
  }

  void TEST_B() {
    ASSERT_EQ(...);
    //...
  }
  ///
};

// the test "runner"
TEST_F(MyTest, main_test) {
  while (simulation()) {
    // modify simulation data
    TEST_A();
    // some other simulation operations
    TEST_B();
  }
}
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top