日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問(wèn) 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 人文社科 > 生活经验 >内容正文

生活经验

Google Test(GTest)使用方法和源码解析——Listener技术分析和应用

發(fā)布時(shí)間:2023/11/27 生活经验 25 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Google Test(GTest)使用方法和源码解析——Listener技术分析和应用 小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

? ? ? ? 在《Google Test(GTest)使用方法和源碼解析——結(jié)果統(tǒng)計(jì)機(jī)制分析》文中,我么分析了GTest如何對(duì)測(cè)試結(jié)果進(jìn)行統(tǒng)計(jì)的。本文我們將解析其結(jié)果輸出所使用到的Listener機(jī)制。(轉(zhuǎn)載請(qǐng)指明出于breaksoftware的csdn博客)

解析

? ? ? ?源碼中,我們經(jīng)常要和UnitTest類打交道。它提供了一個(gè)單例方法返回自己的一個(gè)對(duì)象,然后各處代碼都在調(diào)用這個(gè)單例的方法。所以說(shuō)它是GTest框架中非常重要的銜接環(huán)。而在其內(nèi)部,實(shí)際工作的卻是一個(gè)UnitTestImpl對(duì)象

internal::UnitTestImpl* impl_;

? ? ? ? 該指針在UnitTest構(gòu)造函數(shù)中被新建出來(lái)

UnitTest::UnitTest() {impl_ = new internal::UnitTestImpl(this);
}

? ? ? ? 之后,我們調(diào)用UnitTest單例的方法,很多都是直接調(diào)用該對(duì)象的方法。其構(gòu)造函數(shù)是這么寫(xiě)的

UnitTestImpl::UnitTestImpl(UnitTest* parent): parent_(parent),GTEST_DISABLE_MSC_WARNINGS_PUSH_(4355 /* using this in initializer */)default_global_test_part_result_reporter_(this),default_per_thread_test_part_result_reporter_(this),GTEST_DISABLE_MSC_WARNINGS_POP_()global_test_part_result_repoter_(&default_global_test_part_result_reporter_),per_thread_test_part_result_reporter_(&default_per_thread_test_part_result_reporter_),.......catch_exceptions_(false) {listeners()->SetDefaultResultPrinter(new PrettyUnitTestResultPrinter);
}

? ? ? ? 本文要講解的內(nèi)容將和上面的代碼有很大的關(guān)系。

? ? ? ? 在GTest測(cè)試框架中,它提出了一個(gè)Listener的概念,以供開(kāi)發(fā)者監(jiān)聽(tīng)執(zhí)行過(guò)程。GTest框架就是使用Listener機(jī)制實(shí)現(xiàn)了結(jié)果輸出。我們看下listener基類的設(shè)計(jì)

class TestEventListener {public:virtual ~TestEventListener() {}// Fired before any test activity starts.virtual void OnTestProgramStart(const UnitTest& unit_test) = 0;// Fired before each iteration of tests starts.  There may be more than// one iteration if GTEST_FLAG(repeat) is set. iteration is the iteration// index, starting from 0.virtual void OnTestIterationStart(const UnitTest& unit_test,int iteration) = 0;// Fired before environment set-up for each iteration of tests starts.virtual void OnEnvironmentsSetUpStart(const UnitTest& unit_test) = 0;// Fired after environment set-up for each iteration of tests ends.virtual void OnEnvironmentsSetUpEnd(const UnitTest& unit_test) = 0;// Fired before the test case starts.virtual void OnTestCaseStart(const TestCase& test_case) = 0;// Fired before the test starts.virtual void OnTestStart(const TestInfo& test_info) = 0;// Fired after a failed assertion or a SUCCEED() invocation.virtual void OnTestPartResult(const TestPartResult& test_part_result) = 0;// Fired after the test ends.virtual void OnTestEnd(const TestInfo& test_info) = 0;// Fired after the test case ends.virtual void OnTestCaseEnd(const TestCase& test_case) = 0;// Fired before environment tear-down for each iteration of tests starts.virtual void OnEnvironmentsTearDownStart(const UnitTest& unit_test) = 0;// Fired after environment tear-down for each iteration of tests ends.virtual void OnEnvironmentsTearDownEnd(const UnitTest& unit_test) = 0;// Fired after each iteration of tests finishes.virtual void OnTestIterationEnd(const UnitTest& unit_test,int iteration) = 0;// Fired after all test activities have ended.virtual void OnTestProgramEnd(const UnitTest& unit_test) = 0;
};

? ? ? ? 它暴露了很多接口,每個(gè)都對(duì)應(yīng)于執(zhí)行過(guò)程的一個(gè)狀態(tài),比如OnTestCaseStart,字面意思就是測(cè)試用例執(zhí)行開(kāi)始處(要執(zhí)行自定義邏輯),此處比較適合輸出測(cè)試用例的基本信息;再比如OnTestCaseEnd,是測(cè)試用例執(zhí)行結(jié)束處(要執(zhí)行自定義邏輯),此處比較適合輸出測(cè)試用例的執(zhí)行結(jié)果。

? ? ? ? 在UnitTestImpl構(gòu)造函數(shù)中有個(gè)listeners()函數(shù),其返回了UnitTestImpl類的TestEventListeners成員變量指針。從名字上看可以看出它是一個(gè)Listener的集合,因?yàn)橛脩艨梢孕略鲎远x的Listener,所以要將其設(shè)計(jì)為一個(gè)集合。但是實(shí)際上它只是集合的封裝

class GTEST_API_ TestEventListeners {private:.........// The actual list of listeners.internal::TestEventRepeater* repeater_;// Listener responsible for the standard result output.TestEventListener* default_result_printer_;// Listener responsible for the creation of the XML output file.TestEventListener* default_xml_generator_;
}

? ? ? ? TestEventRepeater才是Listener的集合,同時(shí)它也是繼承于TestEventListener接口類。

class TestEventRepeater : public TestEventListener {public:TestEventRepeater() : forwarding_enabled_(true) {}virtual ~TestEventRepeater();void Append(TestEventListener *listener);TestEventListener* Release(TestEventListener* listener);// Controls whether events will be forwarded to listeners_. Set to false// in death test child processes.bool forwarding_enabled() const { return forwarding_enabled_; }void set_forwarding_enabled(bool enable) { forwarding_enabled_ = enable; }virtual void OnTestProgramStart(const UnitTest& unit_test);virtual void OnTestIterationStart(const UnitTest& unit_test, int iteration);virtual void OnEnvironmentsSetUpStart(const UnitTest& unit_test);virtual void OnEnvironmentsSetUpEnd(const UnitTest& unit_test);virtual void OnTestCaseStart(const TestCase& test_case);virtual void OnTestStart(const TestInfo& test_info);virtual void OnTestPartResult(const TestPartResult& result);virtual void OnTestEnd(const TestInfo& test_info);virtual void OnTestCaseEnd(const TestCase& test_case);virtual void OnEnvironmentsTearDownStart(const UnitTest& unit_test);virtual void OnEnvironmentsTearDownEnd(const UnitTest& unit_test);virtual void OnTestIterationEnd(const UnitTest& unit_test, int iteration);virtual void OnTestProgramEnd(const UnitTest& unit_test);private:// Controls whether events will be forwarded to listeners_. Set to false// in death test child processes.bool forwarding_enabled_;// The list of listeners that receive events.std::vector<TestEventListener*> listeners_;GTEST_DISALLOW_COPY_AND_ASSIGN_(TestEventRepeater);
};

? ? ? ? 這個(gè)類的設(shè)計(jì)也非常有意思,它既在成員變量listeners_中保存了一系列用戶自定義的監(jiān)聽(tīng)者(TestEventListener*對(duì)象指針),又讓自身繼承于TestEventListener,那就是說(shuō)它自己也是一個(gè)Listener。這點(diǎn)比較像大內(nèi)總管,自己是個(gè)太監(jiān),手下也是太監(jiān)。小太監(jiān)要干的活,大內(nèi)總管也要能去做(繼承于TestEventListener),只是大內(nèi)總管不用自己親手去做,而是調(diào)度小太監(jiān)去做。這樣的功能傳遞是通過(guò)類似下面代碼的調(diào)用去實(shí)現(xiàn)的

// Since most methods are very similar, use macros to reduce boilerplate.
// This defines a member that forwards the call to all listeners.
#define GTEST_REPEATER_METHOD_(Name, Type) \
void TestEventRepeater::Name(const Type& parameter) { \if (forwarding_enabled_) { \for (size_t i = 0; i < listeners_.size(); i++) { \listeners_[i]->Name(parameter); \} \} \
}
// This defines a member that forwards the call to all listeners in reverse
// order.
#define GTEST_REVERSE_REPEATER_METHOD_(Name, Type) \
void TestEventRepeater::Name(const Type& parameter) { \if (forwarding_enabled_) { \for (int i = static_cast<int>(listeners_.size()) - 1; i >= 0; i--) { \listeners_[i]->Name(parameter); \} \} \
}

? ? ? ??TestEventRepeater從TestEventListener繼承來(lái)的方法便如此定義

GTEST_REPEATER_METHOD_(OnTestProgramStart, UnitTest)
GTEST_REPEATER_METHOD_(OnEnvironmentsSetUpStart, UnitTest)
GTEST_REPEATER_METHOD_(OnTestCaseStart, TestCase)
GTEST_REPEATER_METHOD_(OnTestStart, TestInfo)
GTEST_REPEATER_METHOD_(OnTestPartResult, TestPartResult)
GTEST_REPEATER_METHOD_(OnEnvironmentsTearDownStart, UnitTest)
GTEST_REVERSE_REPEATER_METHOD_(OnEnvironmentsSetUpEnd, UnitTest)
GTEST_REVERSE_REPEATER_METHOD_(OnEnvironmentsTearDownEnd, UnitTest)
GTEST_REVERSE_REPEATER_METHOD_(OnTestEnd, TestInfo)
GTEST_REVERSE_REPEATER_METHOD_(OnTestCaseEnd, TestCase)
GTEST_REVERSE_REPEATER_METHOD_(OnTestProgramEnd, UnitTest)

? ? ? ? 可以見(jiàn)得這個(gè)大內(nèi)總管,對(duì)于上面的指令只是做了一個(gè)簡(jiǎn)單的判斷就拋給下面每個(gè)小太監(jiān)去做了。

? ? ? ? 說(shuō)個(gè)題外話,個(gè)人覺(jué)得TestEventRepeater中repeater的翻譯,不要叫做“重復(fù)者”,叫“中繼者”比較好。
? ? ? ? 我們?cè)倩仡櫹卤O(jiān)聽(tīng)者的傳遞過(guò)程

listeners()->SetDefaultResultPrinter(new PrettyUnitTestResultPrinter);
void TestEventListeners::SetDefaultResultPrinter(TestEventListener* listener) {if (default_result_printer_ != listener) {// It is an error to pass this method a listener that is already in the// list.delete Release(default_result_printer_);default_result_printer_ = listener;if (listener != NULL)Append(listener);}
}
void TestEventListeners::Append(TestEventListener* listener) {repeater_->Append(listener);
}

? ? ? ??SetDefaultResultPrinter方法看著是傳遞一個(gè)“結(jié)果打印者”,但是它實(shí)際要接受一個(gè)Listener。這個(gè)命名雖然很直觀,但是也讓閱讀代碼的人一下子轉(zhuǎn)不過(guò)彎來(lái):Listener和Printer是一回事啊!

class PrettyUnitTestResultPrinter : public TestEventListener {

? ? ? ??PrettyUnitTestResultPrinter各個(gè)事件處理函數(shù)我就不羅列了,它們就是一些結(jié)果輸出。有興趣的同學(xué)可以自己查看。

? ? ? ? 然后我們?cè)賮?lái)看框架中是如何“觸發(fā)”這些事件的。

? ? ? ? 首先是UnitTestImpl::RunAllTests()函數(shù),它處理了幾個(gè)比較大級(jí)別的事件,比如程序啟動(dòng)和結(jié)束

bool UnitTestImpl::RunAllTests() {......TestEventListener* repeater = listeners()->repeater();......repeater->OnTestProgramStart(*parent_);......for (int i = 0; forever || i != repeat; i++) {  ......  repeater->OnTestIterationStart(*parent_, i);  ......  	if (has_tests_to_run) {// Sets up all environments beforehand.repeater->OnEnvironmentsSetUpStart(*parent_);ForEach(environments_, SetUpEnvironment);repeater->OnEnvironmentsSetUpEnd(*parent_);	// Runs the tests only if there was no fatal failure during global// set-up.if (!Test::HasFatalFailure()) {for (int test_index = 0; test_index < total_test_case_count();test_index++) {GetMutableTestCase(test_index)->Run();}}	  // Tears down all environments in reverse order afterwards.repeater->OnEnvironmentsTearDownStart(*parent_);std::for_each(environments_.rbegin(), environments_.rend(),TearDownEnvironment);repeater->OnEnvironmentsTearDownEnd(*parent_);	  }...... repeater->OnTestIterationEnd(*parent_, i);	...... }...... repeater->OnTestProgramEnd(*parent_);...... 
}

? ? ? ? 然后GetMutableTestCase(test_index)->Run();進(jìn)入每個(gè)測(cè)試用例的運(yùn)行,它只處理了OnTestCaseStart和OnTestCaseEnd兩個(gè)事件

void TestCase::Run() {...... internal::UnitTestImpl* const impl = internal::GetUnitTestImpl();...... TestEventListener* repeater = UnitTest::GetInstance()->listeners().repeater();...... repeater->OnTestCaseStart(*this);...... const internal::TimeInMillis start = internal::GetTimeInMillis();for (int i = 0; i < total_test_count(); i++) {GetMutableTestInfo(i)->Run();}...... repeater->OnTestCaseEnd(*this);...... 
}

? ? ? ??GetMutableTestInfo(i)->Run();方法進(jìn)入測(cè)試特例運(yùn)行,它只處理了OnTestStart和OnTestEnd

void TestInfo::Run() {...... // Tells UnitTest where to store test result.internal::UnitTestImpl* const impl = internal::GetUnitTestImpl();...... TestEventListener* repeater = UnitTest::GetInstance()->listeners().repeater();// Notifies the unit test event listeners that a test is about to start.repeater->OnTestStart(*this);...... // Runs the test only if the test object was created and its// constructor didn't generate a fatal failure.if ((test != NULL) && !Test::HasFatalFailure()) {// This doesn't throw as all user code that can throw are wrapped into// exception handling code.test->Run();}...... // Notifies the unit test event listener that a test has just finished.repeater->OnTestEnd(*this);...... 
}

? ? ? ??test->Run();進(jìn)入了我們自定義的測(cè)試實(shí)體,其內(nèi)部通過(guò)層層傳導(dǎo)UnitTestImpl的global_test_part_result_repoter_的函數(shù)中

void DefaultGlobalTestPartResultReporter::ReportTestPartResult(const TestPartResult& result) {unit_test_->current_test_result()->AddTestPartResult(result);unit_test_->listeners()->repeater()->OnTestPartResult(result);
}

? ? ? ? 如此,我們便將listener的運(yùn)行機(jī)制給講完了。順便我們也分析了GTest默認(rèn)結(jié)果輸出的實(shí)現(xiàn)。

應(yīng)用

? ? ? ? 要使用Listener技術(shù),我們需要實(shí)現(xiàn)一個(gè)繼承于?testing::TestEventListener 或testing::EmptyTestEventListener的類。如果繼承于testing::TestEventListener,則需要我們實(shí)現(xiàn)所有純虛方法;而如果繼承于testing::EmptyTestEventListener,則我們只要關(guān)注于部分我們關(guān)心的函數(shù)實(shí)現(xiàn)即可——因?yàn)樗呀?jīng)把所有純虛方法實(shí)現(xiàn)為空方法了。

class MinimalistPrinter : public ::testing::EmptyTestEventListener {// Called before a test starts.virtual void OnTestStart(const ::testing::TestInfo& test_info) {printf("*** Test %s.%s starting.\n",test_info.test_case_name(), test_info.name());}// Called after a failed assertion or a SUCCEED() invocation.virtual void OnTestPartResult(const ::testing::TestPartResult& test_part_result) {printf("%s in %s:%d\n%s\n",test_part_result.failed() ? "*** Failure" : "Success",test_part_result.file_name(),test_part_result.line_number(),test_part_result.summary());}// Called after a test ends.virtual void OnTestEnd(const ::testing::TestInfo& test_info) {printf("*** Test %s.%s ending.\n",test_info.test_case_name(), test_info.name());}
};

? ? ? ? 然后我們就需要在main函數(shù)中將該Listener的對(duì)象加入到框架中。此處有個(gè)地方需要注意下,由于Listener是個(gè)列表,那就意味著一堆Listener將會(huì)被執(zhí)行,其中包括GTest默認(rèn)的Listener——之前結(jié)果輸出的實(shí)現(xiàn)者。如果我們只想讓我們自定義的Listener執(zhí)行,則要先將默認(rèn)Listener去掉(下面代碼第3行)。

  ::testing::TestEventListeners& listeners =::testing::UnitTest::GetInstance()->listeners();delete listeners.Release(listeners.default_result_printer());listeners.Append(new MinimalistPrinter);

? ? ? ? 這兒有個(gè)一個(gè)要注意的是:除了OnTestPartResult()之外的函數(shù),都可以使用GTest判斷類宏進(jìn)行數(shù)據(jù)判斷。唯獨(dú)OnTestPartResult()里不可以,否則會(huì)造成OnTestPartResult()被遞歸調(diào)用。

總結(jié)

以上是生活随笔為你收集整理的Google Test(GTest)使用方法和源码解析——Listener技术分析和应用的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。

如果覺(jué)得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。