Google Test(GTest)使用方法和源码解析——参数自动填充技术分析和应用
? ? ? ? 在我們設計測試用例時,我們需要考慮很多場景。每個場景都可能要細致地考慮到到各個參數的選擇。比如我們希望使用函數IsPrime檢測10000以內字的數字,難道我們要寫一萬行代碼么?(轉載請指明出于breaksoftware的csdn博客)
EXPECT_TRUE(IsPrime(0));
EXPECT_TRUE(IsPrime(1));
EXPECT_TRUE(IsPrime(2));
......
EXPECT_TRUE(IsPrime(9999));
? ? ? ? 這種寫法明顯是不合理的。GTest框架當然也會考慮到這點,它設計了一套自動生成上述檢測的機制,讓我們用很少的代碼就可以解決這個問題。
參數自動填充機制應用
? ? ? ? 我們先從應用的角度講解其使用。首先我們設計一個需要被測試的類
class Bis {
public:bool Even(int n) {if (n % 2 == 0) {return true;}else {return false;}};bool Suc(bool suc) {return suc;}
};
? ? ? ? 該類暴露了兩個返回bool類型的方法:Even用于判斷是否是偶數;Suc只是返回傳入的參數。
? ? ? ? 由于GTest要求提供測試的類要繼承于::testing::Test,于是我們定義一個代理類,它只是繼承于::testing::Test和Bis,代理Bis完成相關調用。
class TestClass : public Bis,public ::testing::Test {
};
bool型入參 ?
? ? ? ? Suc函數的入參類型是bool,于是我們可以新建一個測試用例類,讓它繼承于template <typename T> class WithParamInterface模板類,并把模板指定為bool
class CheckBisSuc :public TestClass,public ::testing::WithParamInterface<bool>
{
};
? ? ? ? 我們再設置一個測試特例,在特例中使用GetParam()方法獲取框架指定的參數
TEST_P(CheckBisSuc, Test) {EXPECT_TRUE(Suc(GetParam()));
}
? ? ? ? 最后,我們使用INSTANTIATE_TEST_CASE_P宏向框架注冊“定制化測試”
INSTANTIATE_TEST_CASE_P(TestBisBool, CheckBisSuc, Bool());
? ? ? ? 該宏的第一個參數是測試前綴,第二個參數是測試類名,第三個參數是參數生成規則。如此我們就相當于執行了
EXPECT_TRUE(Suc(true));EXPECT_TRUE(Suc(false));
可選擇入參 ? ? ? ?
? ? ? ? 我們再看下針對Even函數的測試。我們要定義一個繼承于template <typename T> class WithParamInterface模板類的類CheckBisEven,用于指定Even的入參類型為int
class CheckBisEven :public TestClass,public ::testing::WithParamInterface<int>
{
};
? ? ? ? 然后我們建立一個針對該類的測試特例
TEST_P(CheckBisEven, Test) {EXPECT_TRUE(Even(GetParam()));
}
? ? ? ? 最后我們可以使用Range、Values或者ValuesIn的方式指定Even的參數值
INSTANTIATE_TEST_CASE_P(TestBisValuesRange, CheckBisEven, Range(0, 9, 2));INSTANTIATE_TEST_CASE_P(TestBisValues, CheckBisEven, Values(11, 12, 13, 14));int values[] = {0, 1};
INSTANTIATE_TEST_CASE_P(TestBisValuesIn, CheckBisEven, ValuesIn(values));int moreValues[] = {0,1,2,3,4,5,6,7,8,9,10};
vector<int> IntVecValues(moreValues, moreValues + sizeof(moreValues));
INSTANTIATE_TEST_CASE_P(TestBisValuesInVector, CheckBisEven, ValuesIn(IntVecValues));
? ? ? ? Range的第一個參數是起始參數值,第二個值是結束參數值,第三個參數是遞增值。于是Range這組測試測試的是0、2、4、6、8這些入參。如果第三個參數沒有, 則默認是遞增1。
? ? ? ? Values中羅列的是將被選擇作為參數的值。
? ? ? ? ValuesIn的參數是個容器或者容器的起始迭代器和結束迭代器。
參數組合
? ? ? ? 參數組合要求編譯器支持tr/tuple,所以一些不支持tr庫的編譯器將無法使用該功能。
? ? ? ? 什么是參數組合?顧名思義,就是將不同參數集組合在一起衍生出多維的數據。比如(true,false)和(1,2)可以組合成(true,1)、(true,2)、(false,1)和(false,2)等四種參數組合,然后我們使用這四組數據進行測試。
? ? ? ? 我們看個例子,首先我們要定義一個待測類。需要注意的是,它繼承了模板類TestWithParam,且模板參數是組合的類型::testing::tuple<bool, int>。這個類并沒有繼承Bis,而是讓Bis成為其成員變量,在checkData函數中檢測Bis的各個函數
class CombineTest : public TestWithParam< ::testing::tuple<bool, int> > {
protected:bool checkData() {bool suc = ::testing::get<0>(GetParam());int n = ::testing::get<1>(GetParam());return bis.Suc(suc) && bis.Even(n);}
private:Bis bis;
};
? ? ? ? 然后我們定義一個(true,false)和(1,2,3,4)組合測試
TEST_P(CombineTest, Test) {EXPECT_TRUE(checkData());
}INSTANTIATE_TEST_CASE_P(TestBisValuesCombine, CombineTest, Combine(Bool(), Values(0, 1, 2, 3, 4)));
? ? ? ? 如何我們便可以衍生出8組測試。我們看下部分測試結果輸出
[----------] 8 tests from TestBisValuesCombine/CombineTest
......
[ RUN ] TestBisValuesCombine/CombineTest.Test/6
[ OK ] TestBisValuesCombine/CombineTest.Test/6 (0 ms)
[ RUN ] TestBisValuesCombine/CombineTest.Test/7
../samples/sample11_unittest.cc:175: Failure
Value of: checkData()Actual: false
Expected: true
[ FAILED ] TestBisValuesCombine/CombineTest.Test/7, where GetParam() = (true, 3) (1 ms)
[----------] 8 tests from TestBisValuesCombine/CombineTest (2 ms total)
? ? ? ?上例中TestBisValuesCombine/CombineTest是最終的測試用例名,Test/6和Test/7是其下兩個測試特例名。
? ? ? ?我們最后把參數生成函數羅列下
| Range(begin, end[, step]) | Yields values {begin, begin+step, begin+step+step, ...}. The values do not include end. step defaults to 1. |
| Values(v1, v2, ..., vN) | Yields values {v1, v2, ..., vN}. |
| ValuesIn(container) and ValuesIn(begin, end) | Yields values from a C-style array, an STL-style container, or an iterator range [begin, end). container, begin, and end can be expressions whose values are determined at run time. |
| Bool() | Yields sequence {false, true}. |
| Combine(g1, g2, ..., gN) | Yields all combinations (the Cartesian product for the math savvy) of the values generated by the N generators. This is only available if your system provides the <tr1/tuple> header. If you are sure your system does, and Google Test disagrees, you can override it by defining GTEST_HAS_TR1_TUPLE=1. See comments in include/gtest/internal/gtest-port.h for more information. |
參數自動填充機制解析
? ? ? ? 該機制和之前介紹的各種技術都不同,所以我們還要從函數注冊、自動調用等基礎方面去解析。
注冊
? ? ? ? 之前的博文中,我們都是使用TEST宏。它幫我們完成了測試類的注冊和測試實體的組織(詳見《Google Test(GTest)使用方法和源碼解析——自動調度機制分析》)。本節我們使用的都是TEST_P宏,其實現方式和TEST宏有類似的地方
- 都定義了一個測試類
- 都聲明了一個虛方法——TestBody
- 都將賦值符設置為私有
- 都在末尾定了TestBody函數體的一部分,要求用戶去填充測試實體
# define TEST_P(test_case_name, test_name) \class GTEST_TEST_CLASS_NAME_(test_case_name, test_name) \: public test_case_name { \public: \GTEST_TEST_CLASS_NAME_(test_case_name, test_name)() {} \virtual void TestBody(); \private:GTEST_DISALLOW_COPY_AND_ASSIGN_(\GTEST_TEST_CLASS_NAME_(test_case_name, test_name)); \
......void GTEST_TEST_CLASS_NAME_(test_case_name, test_name)::TestBody()
? ? ? ? 不同的地方便是TestBody方法由私有變成公有,還有就是類的注冊
private: \static int AddToRegistry() { \::testing::UnitTest::GetInstance()->parameterized_test_registry(). \GetTestCasePatternHolder<test_case_name>(\#test_case_name, \::testing::internal::CodeLocation(\__FILE__, __LINE__))->AddTestPattern(\#test_case_name, \#test_name, \new ::testing::internal::TestMetaFactory< \GTEST_TEST_CLASS_NAME_(\test_case_name, test_name)>()); \return 0; \} \static int gtest_registering_dummy_ GTEST_ATTRIBUTE_UNUSED_; \
......}; \int GTEST_TEST_CLASS_NAME_(test_case_name, \test_name)::gtest_registering_dummy_ = \GTEST_TEST_CLASS_NAME_(test_case_name, test_name)::AddToRegistry(); \
? ? ? ? TEST_P宏暴露出來的靜態變量gtest_registering_dummy_明顯只是一個輔助,它的真正目的只是為了讓其可以在main函數之前初始化,并在初始化函數中完成類的注冊。而注冊函數也是實現在TEST_P定義的類的內部,但是是個靜態成員函數。
? ? ? ? 注冊過程中,單例UnitTest調用了parameterized_test_registry方法返回一個ParameterizedTestCaseRegistry對象引用。它是參數自動填充機制類(之后稱Parameterized類)的注冊場所。其內部變量test_case_infos_保存了所有Parameterized類對象的指針
private:typedef ::std::vector<ParameterizedTestCaseInfoBase*> TestCaseInfoContainer;TestCaseInfoContainer test_case_infos_;
? ? ? ? 該類還暴露了一個非常重要的方法GetTestCasePatternHolder,它用于返回一個測試用例對象指針
template <class TestCase>ParameterizedTestCaseInfo<TestCase>* GetTestCasePatternHolder(const char* test_case_name,CodeLocation code_location) {ParameterizedTestCaseInfo<TestCase>* typed_test_info = NULL;for (TestCaseInfoContainer::iterator it = test_case_infos_.begin();it != test_case_infos_.end(); ++it) {if ((*it)->GetTestCaseName() == test_case_name) {if ((*it)->GetTestCaseTypeId() != GetTypeId<TestCase>()) {// Complain about incorrect usage of Google Test facilities// and terminate the program since we cannot guaranty correct// test case setup and tear-down in this case.ReportInvalidTestCaseType(test_case_name, code_location);posix::Abort();} else {// At this point we are sure that the object we found is of the same// type we are looking for, so we downcast it to that type// without further checks.typed_test_info = CheckedDowncastToActualType<ParameterizedTestCaseInfo<TestCase> >(*it);}break;}}if (typed_test_info == NULL) {typed_test_info = new ParameterizedTestCaseInfo<TestCase>(test_case_name, code_location);test_case_infos_.push_back(typed_test_info);}return typed_test_info;}
? ? ? ? 該方法是個模板方法,模板是我們通過TEST_P傳入的測試用例類。它通過我們傳入的測試用例名和代碼所在行數等信息,創建一個或者返回一個已存在的ParameterizedTestCaseInfo<T>*類型的數據,其指向了符合以上信息的測試用例對象。這個對象內部保存了一系列測試特例類指針
typedef ::std::vector<linked_ptr<TestInfo> > TestInfoContainer;
TestInfoContainer tests_;
? ? ? ? TEST_P宏通過該對象,調用AddTestPattern方法向測試用例對象新增當前測試特例對象
void AddTestPattern(const char* test_case_name,const char* test_base_name,TestMetaFactoryBase<ParamType>* meta_factory) {tests_.push_back(linked_ptr<TestInfo>(new TestInfo(test_case_name,test_base_name,meta_factory)));}
? ? ? ? 這個過程和TEST宏的思路基本一致,不同的是它引入了很多模板。但是需要注意的是,這并不是向框架的可執行隊列中插入測試用例或者測試測試特例信息的地方,這只是中間臨時保存的過程。
? ? ? ? 我們再看看INSTANTIATE_TEST_CASE_P的實現,它首先定義了一個返回參數生成器的函數
# define INSTANTIATE_TEST_CASE_P(prefix, test_case_name, generator, ...) \::testing::internal::ParamGenerator<test_case_name::ParamType> \gtest_##prefix##test_case_name##_EvalGenerator_() { return generator; } \
? ? ? ? 這個函數非常重要,之后我們就靠它生成參數。
? ? ? ? 然后定義了一個返回參數名稱的函數
::std::string gtest_##prefix##test_case_name##_EvalGenerateName_( \const ::testing::TestParamInfo<test_case_name::ParamType>& info) { \return ::testing::internal::GetParamNameGen<test_case_name::ParamType> \(__VA_ARGS__)(info); \} \
? ? ? ? 最后它定義了一個全局傀儡變量,在其初始化時,搶在main函數執行之前注冊相關信息
int gtest_##prefix##test_case_name##_dummy_ GTEST_ATTRIBUTE_UNUSED_ = \::testing::UnitTest::GetInstance()->parameterized_test_registry(). \GetTestCasePatternHolder<test_case_name>(\#test_case_name, \::testing::internal::CodeLocation(\__FILE__, __LINE__))->AddTestCaseInstantiation(\#prefix, \>est_##prefix##test_case_name##_EvalGenerator_, \>est_##prefix##test_case_name##_EvalGenerateName_, \__FILE__, __LINE__)
? ? ? ? 可見它也是通過測試用例的類名獲取我們之前通過TEST_P創建的測試用例類對象,然后調用AddTestCaseInstantiation方法,傳入參數生成函數指針(參數生成器)和參數名生成函數指針。通過這些信息,將新建一個定制化(Instantiation)的測試對象——Instantiationinfo。AddTestCaseInstantiation將該定制化測試對象保存到template <class TestCase>?class ParameterizedTestCaseInfo類里成員變量中。
// INSTANTIATE_TEST_CASE_P macro uses AddGenerator() to record information// about a generator.int AddTestCaseInstantiation(const string& instantiation_name,GeneratorCreationFunc* func,ParamNameGeneratorFunc* name_func,const char* file,int line) {instantiations_.push_back(InstantiationInfo(instantiation_name, func, name_func, file, line));return 0; // Return value used only to run this method in namespace scope.}typedef ::std::vector<InstantiationInfo> InstantiationContainer;InstantiationContainer instantiations_;
? ? ? ? 至此,我們把所有在main函數之前執行的操作給看完了。但是仍然沒有發現GTest框架是如何將這些臨時信息保存到執行隊列中的,更沒有看到調度的代碼。
歸類及再注冊
? ? ? ? 最后我們在main函數的testing::InitGoogleTest(&argc, argv);中發現如下代碼
GetUnitTestImpl()->PostFlagParsingInit();
? ? ? ? PostFlagParsingInit最終將會調用到
void UnitTestImpl::RegisterParameterizedTests() {
#if GTEST_HAS_PARAM_TESTif (!parameterized_tests_registered_) {parameterized_test_registry_.RegisterTests();parameterized_tests_registered_ = true;}
#endif
}
? ? ? ? parameterized_test_registry_就是之前在TEST_P和INSTANTIATE_TEST_CASE_P宏中使用到的::testing::UnitTest::GetInstance()->parameterized_test_registry()的返回值,我們看看RegisterTests()里干了什么
void RegisterTests() {for (TestCaseInfoContainer::iterator it = test_case_infos_.begin();it != test_case_infos_.end(); ++it) {(*it)->RegisterTests();}}
? ? ? ? 它遍歷了所有通過TEST_P保存的測試用例對象(ParameterizedTestCaseInfo<T>),然后逐個調用其RegisterTests方法
virtual void RegisterTests() {for (typename TestInfoContainer::iterator test_it = tests_.begin();test_it != tests_.end(); ++test_it) {linked_ptr<TestInfo> test_info = *test_it;
? ? ? ? 一開始它枚舉了所有之前通過TEST_P保存的測試特例對象,之后都會對該對象進行操作
for (typename InstantiationContainer::iterator gen_it =instantiations_.begin(); gen_it != instantiations_.end();++gen_it) {const string& instantiation_name = gen_it->name;ParamGenerator<ParamType> generator((*gen_it->generator)());ParamNameGeneratorFunc* name_func = gen_it->name_func;const char* file = gen_it->file;int line = gen_it->line;string test_case_name;if ( !instantiation_name.empty() )test_case_name = instantiation_name + "/";test_case_name += test_info->test_case_base_name;size_t i = 0;std::set<std::string> test_param_names;
? ? ? ? 然后枚舉該測試用例中所有通過INSTANTIATE_TEST_CASE_P宏保存的定制化測試對象,并準備好相關數據供之后使用。
for (typename ParamGenerator<ParamType>::iterator param_it =generator.begin();param_it != generator.end(); ++param_it, ++i) {Message test_name_stream;std::string param_name = name_func(TestParamInfo<ParamType>(*param_it, i));GTEST_CHECK_(IsValidParamName(param_name))<< "Parameterized test name '" << param_name<< "' is invalid, in " << file<< " line " << line << std::endl;GTEST_CHECK_(test_param_names.count(param_name) == 0)<< "Duplicate parameterized test name '" << param_name<< "', in " << file << " line " << line << std::endl;test_param_names.insert(param_name);test_name_stream << test_info->test_base_name << "/" << param_name;
? ? ? ? 這段代碼遍歷參數生成器,并使用參數名生成器把所有參數轉換成一個string類型數據,插入到待輸出的內容中
調度
? ? ? ?RegisterTests函數最后將調用如下過程
MakeAndRegisterTestInfo(test_case_name.c_str(),test_name_stream.GetString().c_str(),NULL, // No type parameter.PrintToString(*param_it).c_str(),code_location_,GetTestCaseTypeId(),TestCase::SetUpTestCase,TestCase::TearDownTestCase,test_info->test_meta_factory->CreateTestFactory(*param_it));} // for param_it} // for gen_it} // for test_it} // RegisterTests
? ? ? ? MakeAndRegisterTestInfo函數在之前的博文中做過分析,它將所有測試用例和測試特例保存到GTest框架的可執行隊列中,從而完成調度前的所有準備工作。至于調度及MakeAndRegisterTestInfo的細節可以參見《Google Test(GTest)使用方法和源碼解析——自動調度機制分析》。
? ? ? ? 說了這么多理論,我們以之前的例子為例
TEST_P(CheckBisEven, Test) {EXPECT_TRUE(Even(GetParam()));
}int values[] = {0, 1};
INSTANTIATE_TEST_CASE_P(TestBisValuesIn, CheckBisEven, ValuesIn(values));
INSTANTIATE_TEST_CASE_P(TestBisValues, CheckBisEven, Values(11, 12, 13, 14));
? ? ? ? 第1行將新建名為CheckBisEven的測試用例。并在該測試用例下新建并保存一個名為CheckBisEven_Test_Test的測試特例。
? ? ? ? 第6、7行將在CheckBisEven測試用例下新增兩個定制化測試對象。至此main函數之前的數據保存工作完畢,但是數據保存在一個臨時區域。
? ? ? ??testing::InitGoogleTest方法遍歷所有的測試用例對象。針對每個測試用例,又遍歷其測試特例對象。對每個測試特例對象,再遍歷這個測試用例中保存的定制化測試對象(上例中有兩個定制化測試對象)。使用定制化測試對象生成參數,通過MakeAndRegisterTestInfo方法將重新組織關系的測試用例和被參數化的測試特例保存到GTest的可執行隊列中。從而在之后被框架自動調度起來。
? ? ? ? 為了區分之前的測試特例,MakeAndRegisterTestInfo使用了新的測試用例和測試特例名。測試用例名的生成規則是(INSTANTIATE_TEST_CASE_P宏的第一個參數/INSTANTIATE_TEST_CASE_P的第二個參數)——上例是TestBisValuesIn/CheckBisEven和TestBisValues/CheckBisEven,測試特例名的生成規則是(TEST_P的第二個參數/當前參數值)——上例是Test/0、Test/1、Test/11、Test/12、Test/13、Test/14。于是上例就會生成兩個測試用例,分別有2個和4個測試特例。每個參數是一個特例。這些才是框架執行的測試對象。
參數傳遞
? ? ? ? 通過上面分析,我們可以得知,TEST_P定義的測試類,可能分屬于兩個不同的測試的特例(上例就分屬于測試用例TestBisValuesIn/CheckBisEven和TestBisValues/CheckBisEven)。于是我們在MakeAndRegisterTestInfo函數調用中看到
test_info->test_meta_factory->CreateTestFactory(*param_it)
? ? ? ? 這行代碼是通過類廠,新建了一個特例對象。
? ? ? ? 我們將重點放到類廠的實現,這將有助于我們發現參數是怎么傳遞的。
? ? ? ? 測試用例信息的類中保存了一系列TestInfo對象,每個TestInfo對象都有一個用于“生成攜帶參數的對象”的類廠——test_meta_factory
template <class TestCase>
class ParameterizedTestCaseInfo : public ParameterizedTestCaseInfoBase {
.......typedef typename TestCase::ParamType ParamType;
.......struct TestInfo {TestInfo(const char* a_test_case_base_name,const char* a_test_base_name,TestMetaFactoryBase<ParamType>* a_test_meta_factory) :......,test_meta_factory(a_test_meta_factory) {}.......const scoped_ptr<TestMetaFactoryBase<ParamType> > test_meta_factory;};
......
}
? ? ? ? 注意下ParamType,它是我們傳入的模板類的一個屬性,即測試用例類的屬性,但是我們好像沒有定義過它。其實我們是通過繼承template <typename T>?class WithParamInterface類來設置該屬性的
template <typename T>
class WithParamInterface {public:typedef T ParamType;
? ? ? ? 回顧下我們測試用例類的設計
class CheckBisEven :public TestClass,public ::testing::WithParamInterface<int>
{
};
? ? ? ? 可見該用例的ParamType就是我們指定的int。框架在不知道我們指定了哪個類型的情況下,選擇了一個替代符實現之后邏輯的,這在模板類設計中經常見到。
? ? ? ? 我們再回到類廠的實現上來。test_meta_factory是在TEST_P宏中使用下列方法新建的
new ::testing::internal::TestMetaFactory< GTEST_TEST_CLASS_NAME_(test_case_name, test_name)>()
? ? ? ??TestMetaFactory的定義如下
template <class TestCase>
class TestMetaFactory: public TestMetaFactoryBase<typename TestCase::ParamType> {public:typedef typename TestCase::ParamType ParamType;
......
};
? ? ? ? 它是個模板類,繼承于另一個模板類TestMetaFactoryBase,TestMetaFactoryBase的模板是TestMetaFactory模板的ParamType屬性,對應于上例就是int。TestMetaFactoryBase類是個接口類,沒什么好說的。
? ? ? ? 在MakeAndRegisterTestInfo注冊測試特例時,使用了該特例的類廠對象調用CreateTestFactory方法
virtual TestFactoryBase* CreateTestFactory(ParamType parameter) {return new ParameterizedTestFactory<TestCase>(parameter);}
? ? ? 它又新建了一個模板類對象指針
template <class TestClass>
class ParameterizedTestFactory : public TestFactoryBase {public:typedef typename TestClass::ParamType ParamType;explicit ParameterizedTestFactory(ParamType parameter) :parameter_(parameter) {}
.....private:const ParamType parameter_;GTEST_DISALLOW_COPY_AND_ASSIGN_(ParameterizedTestFactory);
};
? ? ? ? 新建的類廠對象最終會保存到TestInfo中,并在測試用例執行前被調用,從而生成對應的測試特例對象。這段邏輯在《Google Test(GTest)使用方法和源碼解析——自動調度機制分析》有過分析
void TestInfo::Run() {
.......Test* const test = internal::HandleExceptionsInMethodIfSupported(factory_, &internal::TestFactoryBase::CreateTest,"the test fixture's constructor");
.......
}
? ? ? ? 我們再將關注的重點放到ParameterizedTestFactory 的CreateTest方法,它先通過模板類的SetParam方法設置了參數,然后新建并返回了一個模板類對象。
virtual Test* CreateTest() {TestClass::SetParam(?meter_);return new TestClass();}
? ? ? ? 我們的測試用例類怎么有SetParam方法?其實這也是在我們繼承的WithParamInterface類中實現的
template <typename T>
class WithParamInterface {public:typedef T ParamType;virtual ~WithParamInterface() {}// The current parameter value. Is also available in the test fixture's// constructor. This member function is non-static, even though it only// references static data, to reduce the opportunity for incorrect uses// like writing 'WithParamInterface<bool>::GetParam()' for a test that// uses a fixture whose parameter type is int.const ParamType& GetParam() const {GTEST_CHECK_(parameter_ != NULL)<< "GetParam() can only be called inside a value-parameterized test "<< "-- did you intend to write TEST_P instead of TEST_F?";return *parameter_;}private:// Sets parameter value. The caller is responsible for making sure the value// remains alive and unchanged throughout the current test.static void SetParam(const ParamType* parameter) {parameter_ = parameter;}// Static value used for accessing parameter during a test lifetime.static const ParamType* parameter_;// TestClass must be a subclass of WithParamInterface<T> and Test.template <class TestClass> friend class internal::ParameterizedTestFactory;
};
? ? ? ? 該類保存了一個靜態的全局變量parameter_,它保存了參數的指針。并通過SetParam和GetParam方法設置這個全局參數。
? ? ? ? 于是參數傳遞的過程就很明確了:新建TestInfo前,在一個全局區域保存參數,然后通過GetParam方法獲取該全局變量,從而實現參數的傳遞。
? ? ? ? 其實這兒還有個非常有意思的技術點,就是參數生成器的實現。由于它不是這個框架的重點,而且相關內容也不少,我就不打算在這兒分析了,大家有興趣可以自己看看。?
總結
以上是生活随笔為你收集整理的Google Test(GTest)使用方法和源码解析——参数自动填充技术分析和应用的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Google Test(GTest)使用
- 下一篇: Google Test(GTest)使用