Value-Parameterized Tests, multiple executions annoying

1,330 views
Skip to first unread message

bakerhillpins

unread,
Sep 24, 2013, 4:07:23 PM9/24/13
to googletes...@googlegroups.com
I see in the Value-Parameterized Test documentation that using the same test case (fixture class) results in executing all the test vectors from every INSTANTIATE_TEST_CASE_P statement.

Please note that INSTANTIATE_TEST_CASE_P will instantiate all tests in the given test case, whether their definitions come before or after the INSTANTIATE_TEST_CASE_P statement.

I also see that some sort of notification of this behavior is listed as an enhancement:
http://code.google.com/p/googletest/issues/detail?id=65

I found this behavior non intuitive as the above enhancement suggests. I guess I don't have enough experience with Google Test to know why this behavior is useful. I know that I can combat this by putting all my common code into a base class and then make lots of subclasses, one for each test, thus making my vectors unique for each test but providing the same SetUp/TearDown via inheritance. e.g.  This is useful if your interface constantly changes however, since the templates don't work with multiple inheritance (Why? - templates hurt my brain =P).

class FooTestFixture:  public ::testing::Test
{
public:
    static void SetUpTestCase()  ...
    static void TearDownTestCase()  ...

protected:
    virtual void SetUp() ...
    virtual void TearDown()   ...
....
};
...
class FooTest1 :
    public FooTestFixture,
    public ::testing::WithParamInterface<std::tuple<bool, int, int>>
{};

TEST_P(FooTest1, Test1)

INSTANTIATE_TEST_CASE_P(ParameterizedTest1, FooTest1,
                        ::testing::Combine(
                        ::testing::Bool(),
                        ::testing::Range(1,10)));

Lather, rinse, repeat..

That seems like a lot of clerical text to do something that seems to be the way most would think it was going to behave anyhow. Playing around in the debugger I noted that a simple change can make it a one to one or one to many relationship by simply having the RegisterTests() method in gtest-param-util.h search for test_name == prefix. If equal then it's a one to one for this test.

# define TEST_P(test_case_name, test_name)
# define INSTANTIATE_TEST_CASE_P(prefix, test_case_name, generator)

To orchestrate the specific test with the instantiation as such. (excuse the code, it could be cleaner but it was just a proof of concept and hastily tested). 

  // UnitTest class invokes this method to register tests in this test case
  // test cases right before running tests in RUN_ALL_TESTS macro.
  // This method should not be called more then once on any single
  // instance of a ParameterizedTestCaseInfoBase derived class.
  // UnitTest has a guard to prevent from calling this method more then once.
  virtual void RegisterTests() {
      for (typename TestInfoContainer::iterator test_it = tests_.begin();
          test_it != tests_.end(); ++test_it)
      {
          linked_ptr<TestInfo> test_info = *test_it;

          typename InstantiationContainer::iterator gen_it = instantiations_.begin();
          for ( ; gen_it != instantiations_.end(); ++gen_it)
          {
              if(gen_it->first == test_info->test_base_name)
              {
                  break;
              }
          }

          if(gen_it != instantiations_.end())
          {
              RegisterNow(test_it, gen_it);
          }
          else
          {
              for (typename InstantiationContainer::iterator gen_it =
                  instantiations_.begin(); gen_it != instantiations_.end();
                  ++gen_it) {
                      RegisterNow(test_it, gen_it);
              }
          }
      }
  }

  void RegisterNow(typename TestInfoContainer::iterator test_it,
      typename InstantiationContainer::iterator gen_it) {
          linked_ptr<TestInfo> test_info = *test_it;
          const string& instantiation_name = gen_it->first;
          ParamGenerator<ParamType> generator((*gen_it->second)());

          string test_case_name;
          if ( !instantiation_name.empty() )
              test_case_name = instantiation_name + "/";
          test_case_name += test_info->test_case_base_name;

          int i = 0;
          for (typename ParamGenerator<ParamType>::iterator param_it =
              generator.begin();
              param_it != generator.end(); ++param_it, ++i) {
                  Message test_name_stream;
                  test_name_stream << test_info->test_base_name << "/" << i;
                  MakeAndRegisterTestInfo(
                      test_case_name.c_str(),
                      test_name_stream.GetString().c_str(),
                      NULL,  // No type parameter.
                      PrintToString(*param_it).c_str(),
                      GetTestCaseTypeId(),
                      TestCase::SetUpTestCase,
                      TestCase::TearDownTestCase,
                      test_info->test_meta_factory->CreateTestFactory(*param_it));
          }  // for param_it
  }  // for gen_it

I also noted that I don't see any tests for the Value-Parameterized Tests included in the code base??

Cheers,
Bryan

Reply all
Reply to author
Forward
0 new messages