GTest原始碼剖析(六)——RUN_ALL_TESTS
阿新 • • 發佈:2019-01-27
GTest原始碼剖析——RUN_ALL_TESTS
1 RUN_ALL_TESTS()原始碼分析
RUN_ALL_TESTS()之前是巨集定義,現在改變為函式。其實際上僅僅是呼叫了UnitTest單例的Run()函式。
原始碼如下:
其實現為獲取一個UnitTest單例,然後呼叫其Run()函式
int RUN_ALL_TESTS();
inline int RUN_ALL_TESTS()
{
return ::testing::UnitTest::GetInstance()->Run();
}
實際上,RUN_ALL_TESTS()的操作主要是,依次呼叫
1. UnitTest::Run()
2. UnitTest::Run()
3. UnitTestImpl::RunAllTests()
4. TestCase::Run()
5. TestCase::Run()
6. Test::Run()
7. Test::TestBody()
並在這些函式裡設定相應的操作,以保證測試執行的正確性。
1.1 UnitTest::Run()
UnitTest::Run()主要設定了相關死亡測試的設定。真正的實現交給了RunAllTest()
- 如果忽略死亡測試和支援跨平臺及異常處理的邏輯,其實現可以簡化為:
int UnitTest::Run()
{
return internal::HandleExceptionsInMethodIfSupported(
impl(),
&internal::UnitTestImpl::RunAllTests,
"auxiliary test code (environments or event listeners)") ? 0 : 1;
}
- 如果我們在剔除HandleExceptionsInMethodIfSupported對支援跨平臺及異常處理的邏輯,其實現直接簡化為:
int UnitTest::Run()
{
return impl->RunAllTests();
}
- 全部原始碼如下:
int UnitTest::Run()
{
const bool in_death_test_child_process = GTEST_FLAG(internal_run_death_test).length() > 0 ;
const internal::ScopedPrematureExitFile premature_exit_file(
in_death_test_child_process ?
NULL : internal::posix::GetEnv("TEST_PREMATURE_EXIT_FILE"));
impl()->set_catch_exceptions(GTEST_FLAG(catch_exceptions));
#if GTEST_HAS_SEH
if (impl()->catch_exceptions() || in_death_test_child_process)
{
# if !GTEST_OS_WINDOWS_MOBILE && !GTEST_OS_WINDOWS_PHONE && !GTEST_OS_WINDOWS_RT
SetErrorMode(SEM_FAILCRITICALERRORS | SEM_NOALIGNMENTFAULTEXCEPT |
SEM_NOGPFAULTERRORBOX | SEM_NOOPENFILEERRORBOX);
# endif
# if (defined(_MSC_VER) || GTEST_OS_WINDOWS_MINGW) && !GTEST_OS_WINDOWS_MOBILE
_set_error_mode(_OUT_TO_STDERR);
# endif
# if _MSC_VER >= 1400 && !GTEST_OS_WINDOWS_MOBILE
if (!GTEST_FLAG(break_on_failure))
_set_abort_behavior(0x0, flags:_WRITE_ABORT_MSG | _CALL_REPORTFAULT);
# endif
}
#endif // GTEST_HAS_SEH
return internal::HandleExceptionsInMethodIfSupported(
impl(),
&internal::UnitTestImpl::RunAllTests,
"auxiliary test code (environments or event listeners)") ? 0 : 1;
}
1.2 HandleExceptionsInMethodIfSupported
HandleSehExceptionsInMethodIfSupported 主要用於捕獲異常和跨平臺處理。
這裡可以看出GTest對於跨平臺的支援和捕獲異常的不遺餘力。其實這麼多程式碼主要是為了實現如下的功能:
Result HandleExceptionsInMethodIfSupported(T* object, Result (T::*method)(), const char* location) {
return (object->*method)();
}
全部原始碼如下:
template <class T, typename Result>
Result HandleExceptionsInMethodIfSupported(T* object, Result (T::*method)(), const char* location) {
if (internal::GetUnitTestImpl()->catch_exceptions())
{
#if GTEST_HAS_EXCEPTIONS
try
{
return HandleSehExceptionsInMethodIfSupported(object, method, location);
}
catch (const internal::GoogleTestFailureException&)
{
throw;
}
catch (const std::exception& e)
{
internal::ReportFailureInUnknownLocation(
TestPartResult::kFatalFailure,
FormatCxxExceptionMessage(e.what(), location));
}
catch (...)
{
internal::ReportFailureInUnknownLocation(
TestPartResult::kFatalFailure,
FormatCxxExceptionMessage(NULL, location));
}
return static_cast<Result>(0);
#else
return HandleSehExceptionsInMethodIfSupported(object, method, location);
#endif // GTEST_HAS_EXCEPTIONS
}
else
{
return (object->*method)();
}
}
//HandleSehExceptionsInMethodIfSupported 主要用於捕獲異常。
template <class T, typename Result>
Result HandleSehExceptionsInMethodIfSupported(
T* object, Result (T::*method)(), const char* location)
{
#if GTEST_HAS_SEH
__try
{
return (object->*method)();
}
__except (internal::UnitTestOptions::GTestShouldProcessSEH( GetExceptionCode()))
{
std::string* exception_message = FormatSehExceptionMessage(
GetExceptionCode(), location);
internal::ReportFailureInUnknownLocation(TestPartResult::kFatalFailure,
*exception_message);
delete exception_message;
return static_cast<Result>(0);
}
#else
(void)location;
return (object->*method)();
#endif // GTEST_HAS_SEH
}
1.3 UnitTestImpl::RunAllTests()
bool UnitTestImpl::RunAllTests()
{
// Makes sure InitGoogleTest() was called.
if (!GTestIsInitialized())
{
printf("%s",
"\nThis test program did NOT call ::testing::InitGoogleTest "
"before calling RUN_ALL_TESTS(). Please fix it.\n");
return false;
}
// Do not run any test if the --help flag was specified.
if (g_help_flag)
return true;
// Repeats the call to the post-flag parsing initialization in case the
// user didn't call InitGoogleTest.
PostFlagParsingInit();
// Even if sharding is not on, test runners may want to use the
// GTEST_SHARD_STATUS_FILE to query whether the test supports the sharding
// protocol.
internal::WriteToShardStatusFileIfNeeded();
//執行死亡測試
bool in_subprocess_for_death_test = false;
#if GTEST_HAS_DEATH_TEST
in_subprocess_for_death_test = (internal_run_death_test_flag_.get() != NULL);
# if defined(GTEST_EXTRA_DEATH_TEST_CHILD_SETUP_)
if (in_subprocess_for_death_test)
{
GTEST_EXTRA_DEATH_TEST_CHILD_SETUP_();
}
# endif
#endif // GTEST_HAS_DEATH_TEST
//應該是檢查environments相關的設定,可以暫不關心。
const bool should_shard = ShouldShard(kTestTotalShards, kTestShardIndex,
in_subprocess_for_death_test);
//匹配Filter,對所有的測試用例進行匹配,確定是否需要執行該測試用例
const bool has_tests_to_run = FilterTests(should_shard
? HONOR_SHARDING_PROTOCOL
: IGNORE_SHARDING_PROTOCOL) > 0;
// Lists the tests and exits if the --gtest_list_tests flag was specified.
if (GTEST_FLAG(list_tests))
{
ListTestsMatchingFilter();
return true;
}
//設定隨機執行測試用例
random_seed_ = GTEST_FLAG(shuffle) ? GetRandomSeedFromFlag(GTEST_FLAG(random_seed)) : 0;
// True iff at least one test has failed.
bool failed = false;
//獲取事件監聽器,如果使用者訂閱了某事件,則在適當的時間點上報該事件,讓使用者進行額外的操作
TestEventListener* repeater = listeners()->repeater();
start_timestamp_ = GetTimeInMillis();
//上報事件OnTestProgramStart
repeater->OnTestProgramStart(*parent_);
const int repeat = in_subprocess_for_death_test ? 1 : GTEST_FLAG(repeat);
const bool forever = repeat < 0;
for (int i = 0; forever || i != repeat; i++)
{
//清除所有非AddHoc的測試結果,為後續執行做準備。
ClearNonAdHocTestResult();
const TimeInMillis start = GetTimeInMillis();
// Shuffles test cases and tests if requested.
if (has_tests_to_run && GTEST_FLAG(shuffle))
{
random()->Reseed(random_seed_);
ShuffleTests();
}
// Tells the unit test event listeners that the tests are about to start.
repeater->OnTestIterationStart(*parent_, i);
// Runs each test case if there is at least one test to run.
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())
{
//逐個執行TestCase,即最終執行所有的TestBody()
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_);
}
elapsed_time_ = GetTimeInMillis() - start;
// Tells the unit test event listener that the tests have just finished.
repeater->OnTestIterationEnd(*parent_, i);
// Gets the result and clears it.
if (!Passed())
{
failed = true;
}
UnshuffleTests();
if (GTEST_FLAG(shuffle))
{
// Picks a new random seed for each iteration.
random_seed_ = GetNextRandomSeed(random_seed_);
}
}
//上報事件OnTestProgramEnd
repeater->OnTestProgramEnd(*parent_);
return !failed;
}
1.5 TestCase::Run()
// Runs every test in this TestCase.
void TestCase::Run()
{
if (!should_run_) return;
internal::UnitTestImpl* const impl = internal::GetUnitTestImpl();
impl->set_current_test_case(this);
TestEventListener* repeater = UnitTest::GetInstance()->listeners().repeater();
//上報事件OnTestCaseStart
repeater->OnTestCaseStart(*this);
impl->os_stack_trace_getter()->UponLeavingGTest();
//for TEST_F
internal::HandleExceptionsInMethodIfSupported(
this, &TestCase::RunSetUpTestCase, "SetUpTestCase()");
const internal::TimeInMillis start = internal::GetTimeInMillis();
//逐個執行TestCase裡的Test,即最終執行所有的TestBody()
for (int i = 0; i < total_test_count(); i++)
{
GetMutableTestInfo(i)->Run();
}
elapsed_time_ = internal::GetTimeInMillis() - start;
impl->os_stack_trace_getter()->UponLeavingGTest();
//for TEST_F
internal::HandleExceptionsInMethodIfSupported(
this, &TestCase::RunTearDownTestCase, "TearDownTestCase()");
repeater->OnTestCaseEnd(*this);
impl->set_current_test_case(NULL);
}
1.6 TestCase::Run()
void TestInfo::Run()
{
if (!should_run_) return;
// Tells UnitTest where to store test result.
internal::UnitTestImpl* const impl = internal::GetUnitTestImpl();
impl->set_current_test_info(this);
TestEventListener* repeater = UnitTest::GetInstance()->listeners().repeater();
// Notifies the unit test event listeners that a test is about to start.
repeater->OnTestStart(*this);
const TimeInMillis start = internal::GetTimeInMillis();
impl->os_stack_trace_getter()->UponLeavingGTest();
// Creates the test object.
// 此處確保所有的TEST_P裡呼叫GetParam()的正確性
Test* const test = internal::HandleExceptionsInMethodIfSupported(
factory_, &internal::TestFactoryBase::CreateTest,
"the test fixture's constructor");
// 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();
}
// Deletes the test object.
impl->os_stack_trace_getter()->UponLeavingGTest();
internal::HandleExceptionsInMethodIfSupported(
test, &Test::DeleteSelf_, "the test fixture's destructor");
result_.set_elapsed_time(internal::GetTimeInMillis() - start);
// Notifies the unit test event listener that a test has just finished.
repeater->OnTestEnd(*this);
// Tells UnitTest to stop associating assertion results to this
// test.
impl->set_current_test_info(NULL);
}
1.7 Test::Run()
// Runs the test and updates the test result.
void Test::Run()
{
if (!HasSameFixtureClass()) return;
internal::UnitTestImpl* const impl = internal::GetUnitTestImpl();
impl->os_stack_trace_getter()->UponLeavingGTest();
//for TEST_F
internal::HandleExceptionsInMethodIfSupported(this, &Test::SetUp, "SetUp()");
// We will run the test only if SetUp() was successful.
if (!HasFatalFailure())
{
impl->os_stack_trace_getter()->UponLeavingGTest();
internal::HandleExceptionsInMethodIfSupported(
this, &Test::TestBody, "the test body");
}
// However, we want to clean up as much as possible. Hence we will
// always call TearDown(), even if SetUp() or the test body has
// failed.
impl->os_stack_trace_getter()->UponLeavingGTest();
// for TEST_F
internal::HandleExceptionsInMethodIfSupported(
this, &Test::TearDown, "TearDown()");
}
2 參考
ZhaiPillar
2017-09-17