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

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

Domanda

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.

È stato utile?

Soluzione

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();
  }
}
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top