Google test源碼閱讀(一):基本執行流程

我採用的測試代碼如下:

#include <iostream>
#include "gtest.h"

TEST(SimpleTest, Test1)
{
    EXPECT_TRUE(1);
}
TEST(SimpleTest, Test2)
{
    EXPECT_TRUE(2);
}

class FooTest : public ::testing::Test {
protected:
    static void SetUpTestCase() {
        shared_resource_ = new char[1024];
    }
    static void TearDownTestCase() {
        delete [] shared_resource_;
        shared_resource_ = NULL;
    }

    virtual void SetUp() 
    {  
        strcpy(shared_resource_, "SetUp : Called: ");
    }
    virtual void TearDown() 
    {  
        strcpy(shared_resource_, "TearDown : Called: ");
    }

    static char* shared_resource_;
};

char* FooTest::shared_resource_ = NULL;

TEST_F(FooTest, Test1) {
    EXPECT_TRUE(1 < 2)<<"Test1 Equal!";
}

TEST_F(FooTest, Test2) {
    EXPECT_TRUE(2 < 3)<<"Test2 Equal!";
}

GTEST_API_ int main(int argc, char **argv) {
    testing::InitGoogleTest(&argc, argv);
    return RUN_ALL_TESTS();
}

TEST_*,EXPECT_*,RUN_ALL_TESTS等都是Google test framework的內置宏。爲了調試的方便,我們首先進行宏的展開。感謝VS2008內置了宏展開的功能,具體方法如下:

在VS解決方案資源管理器中右擊需要宏展開的文件“xxx.cpp”-->“屬性”-->“配置屬性”-->“C/C++”-->“預處理器”-->“生成預處理文件”-->“帶行號(/P)”或者“不帶行號(/EP /P)”。

右擊“xxx.cpp”文件,選擇編譯。VS2008會在項目文件夾內會一個“xxx.i”文件,對應的宏展開代碼就在此文件中。

展開後的代碼如下:

class SimpleTest_Test1_Test : public ::testing::Test 
{ 
public: SimpleTest_Test1_Test(){} 
private: 
    virtual void TestBody(); 
    static ::testing::TestInfo* const test_info_ ; 
    SimpleTest_Test1_Test(SimpleTest_Test1_Test const &); 
    void operator=(SimpleTest_Test1_Test const &);
};

::testing::TestInfo* const SimpleTest_Test1_Test ::test_info_ = 
    ::testing::internal::MakeAndRegisterTestInfo( 
        "SimpleTest", "Test1", 0, 0, 
        (::testing::internal::GetTestTypeId()), 
        ::testing::Test::SetUpTestCase, 
        ::testing::Test::TearDownTestCase, 
        new ::testing::internal::TestFactoryImpl< SimpleTest_Test1_Test>);

void SimpleTest_Test1_Test::TestBody()
{
    switch (0) 
        case 0: 
        default: if (const ::testing::AssertionResult gtest_ar_ = 
                     ::testing::AssertionResult(1)) ; 
                 else ::testing::internal::AssertHelper(
                     ::testing::TestPartResult::kNonFatalFailure, 
                     "c:\\documents and settings\\xu\\桌面\\gtest_all\\gtest_all\\gtest_main.cc", 
                     6, 
                     ::testing::internal::GetBoolAssertionFailureMessage( 
                        gtest_ar_, "1", "false", "true").c_str()) = ::testing::Message();
}

/////////////////////////////////////////////////////////////////////////////////////////////
class SimpleTest_Test2_Test : public ::testing::Test 
{ 
public: SimpleTest_Test2_Test() {} 
private: 
    virtual void TestBody(); 
    static ::testing::TestInfo* const test_info_ ; 
    SimpleTest_Test2_Test(SimpleTest_Test2_Test const &); 
    void operator=(SimpleTest_Test2_Test const &);
};

::testing::TestInfo* const SimpleTest_Test2_Test ::test_info_ = 
        ::testing::internal::MakeAndRegisterTestInfo( 
            "SimpleTest", "Test2", 0, 0, 
            (::testing::internal::GetTestTypeId()), 
            ::testing::Test::SetUpTestCase, 
            ::testing::Test::TearDownTestCase, 
            new ::testing::internal::TestFactoryImpl< SimpleTest_Test2_Test>);

void SimpleTest_Test2_Test::TestBody()
{
    switch (0) 
        case 0: 
        default: if (const ::testing::AssertionResult gtest_ar_ = 
                     ::testing::AssertionResult(2)) ; 
                 else ::testing::internal::AssertHelper(
                     ::testing::TestPartResult::kNonFatalFailure, 
                     "c:\\documents and settings\\xu\\桌面\\gtest_all\\gtest_all\\gtest_main.cc", 
                     10, 
                     ::testing::internal::GetBoolAssertionFailureMessage( 
                        gtest_ar_, "2", "false", "true").c_str()) = ::testing::Message();
}

/////////////////////////////////////////////////////////////////////////////////////////////
class FooTest : public ::testing::Test {
protected:
    static void SetUpTestCase() {
        shared_resource_ = new char[1024];
    }
    static void TearDownTestCase() {
        delete [] shared_resource_;
        shared_resource_ = 0;
    }

    virtual void SetUp() 
    {  
        strcpy(shared_resource_, "SetUp : Called: ");
    }
    virtual void TearDown() 
    {  
        strcpy(shared_resource_, "TearDown : Called: ");
    }

    static char* shared_resource_;
};

char* FooTest::shared_resource_ = 0;

/////////////////////////////////////////////////////////////////////////////////////////////
class FooTest_Test1_Test : public FooTest 
{ 
public: FooTest_Test1_Test() {} 
private: 
    virtual void TestBody(); 
    static ::testing::TestInfo* const test_info_ ; 
    FooTest_Test1_Test(FooTest_Test1_Test const &); 
    void operator=(FooTest_Test1_Test const &);
};

::testing::TestInfo* const FooTest_Test1_Test ::test_info_ = 
        ::testing::internal::MakeAndRegisterTestInfo( 
            "FooTest", "Test1", 0, 0, 
            (::testing::internal::GetTypeId<FooTest>()), 
            FooTest::SetUpTestCase, 
            FooTest::TearDownTestCase, 
            new ::testing::internal::TestFactoryImpl< FooTest_Test1_Test>);

void FooTest_Test1_Test::TestBody() {
    switch (0) 
        case 0: 
        default: if (const ::testing::AssertionResult gtest_ar_ = 
                     ::testing::AssertionResult(1 < 2)) ; 
                 else ::testing::internal::AssertHelper(
                     ::testing::TestPartResult::kNonFatalFailure, 
                     "c:\\documents and settings\\xu\\桌面\\gtest_all\\gtest_all\\gtest_main.cc", 
                     38, 
                     ::testing::internal::GetBoolAssertionFailureMessage( 
                        gtest_ar_, "1 < 2", "false", "true").c_str()) = ::testing::Message()<<"Test1 Equal!";
}

/////////////////////////////////////////////////////////////////////////////////////////////
class FooTest_Test2_Test : public FooTest 
{ 
public: FooTest_Test2_Test() {} 
private: 
    virtual void TestBody(); 
    static ::testing::TestInfo* const test_info_ ; 
    FooTest_Test2_Test(FooTest_Test2_Test const &); 
    void operator=(FooTest_Test2_Test const &);
};

::testing::TestInfo* const FooTest_Test2_Test ::test_info_ = 
    ::testing::internal::MakeAndRegisterTestInfo( 
        "FooTest", "Test2", 0, 0, 
        (::testing::internal::GetTypeId<FooTest>()), 
        FooTest::SetUpTestCase, 
        FooTest::TearDownTestCase, 
        new ::testing::internal::TestFactoryImpl< FooTest_Test2_Test>);

void FooTest_Test2_Test::TestBody() {
    switch (0) 
        case 0: 
        default: if (const ::testing::AssertionResult gtest_ar_ = 
                     ::testing::AssertionResult(2 < 3)) ; 
                 else ::testing::internal::AssertHelper(
                     ::testing::TestPartResult::kNonFatalFailure, 
                     "c:\\documents and settings\\xu\\桌面\\gtest_all\\gtest_all\\gtest_main.cc", 
                     42, 
                     ::testing::internal::GetBoolAssertionFailureMessage( 
                        gtest_ar_, "2 < 3", "false", "true").c_str()) = ::testing::Message()<<"Test2 Equal!";
}

/////////////////////////////////////////////////////////////////////////////////////////////
int main(int argc, char **argv) {
    testing::InitGoogleTest(&argc, argv);
    return (::testing::UnitTest::GetInstance()->Run());
}

 在進入主函數之前,首先會調用4次MakeAndRegisterTestInfo函數,函數的源代碼如下:

TestInfo* MakeAndRegisterTestInfo( const char* test_case_name, const char* name,
    const char* type_param, const char* value_param, TypeId fixture_class_id, SetUpTestCaseFunc set_up_tc,
    TearDownTestCaseFunc tear_down_tc, TestFactoryBase* factory) {
TestInfo* const test_info = new TestInfo(test_case_name, name, type_param, value_param,        fixture_class_id, factory);
  GetUnitTestImpl()->AddTestInfo(set_up_tc, tear_down_tc, test_info);
  return test_info;
}

 

 

class UnitTestImpl {
…
void AddTestInfo(Test::SetUpTestCaseFunc set_up_tc, Test::TearDownTestCaseFunc tear_down_tc,TestInfo* test_info) {  …
GetTestCase(test_info->test_case_name(), test_info->type_param(), set_up_tc, tear_down_tc)->AddTestInfo(test_info);
}

TestCase* GetTestCase(const char* test_case_name, const char* type_param, Test::SetUpTestCaseFunc set_up_tc, Test::TearDownTestCaseFunc tear_down_tc) {
  // Can we find a TestCase with the given name?
  const std::vector<TestCase*>::const_iterator test_case =
      std::find_if(test_cases_.begin(), test_cases_.end(),
                   TestCaseNameIs(test_case_name)); // 根據TestCaseName的名稱尋找
  if (test_case != test_cases_.end())
    return *test_case;
  // No.  Let's create one.
  TestCase* const new_test_case =
      new TestCase(test_case_name, type_param, set_up_tc, tear_down_tc);
    …
    test_cases_.push_back(new_test_case); 
      test_case_indices_.push_back(static_cast<int>(test_case_indices_.size()));
  return new_test_case;
}
}

 

// Adds a test to this test case.  Will delete the test upon
// destruction of the TestCase object.
void TestCase::AddTestInfo(TestInfo * test_info) {
  test_info_list_.push_back(test_info);
  test_indices_.push_back(static_cast<int>(test_indices_.size()));
}

在進入主函數之前:UnitTestImpl中的vector<TestCase*> test_cases_;擁有的元素如下所示:

 

進入主函數後的執行流程爲:

int UnitTest::Run() {
  …
  return internal::HandleExceptionsInMethodIfSupported( impl(),   &internal::UnitTestImpl::RunAllTests,
      "auxiliary test code (environments or event listeners)") ? 0 : 1;
}
template <class T, typename Result>
Result HandleExceptionsInMethodIfSupported( T* object, Result (T::*method)(), const char* location) {
    …
    return (object->*method)(); 
}
bool UnitTestImpl::RunAllTests() {
   ...
  TestEventListener* repeater = listeners()->repeater();
  repeater->OnTestProgramStart(*parent_);
  // How many times to repeat the tests?  We don't want to repeat them
  // when we are inside the subprocess of a death test.
  const int repeat = in_subprocess_for_death_test ? 1 : GTEST_FLAG(repeat);
  // Repeats forever if the repeat count is negative.
  const bool forever = repeat < 0;
  for (int i = 0; forever || i != repeat; i++) {
    …
    // 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) {
          …
       if (!Test::HasFatalFailure()) {
        for (int test_index = 0; test_index < total_test_case_count();
             test_index++) {
          GetMutableTestCase(test_index)->Run();
        }
      }
          …
    }

    elapsed_time_ = GetTimeInMillis() - start;
    // Tells the unit test event listener that the tests have just finished.
    repeater->OnTestIterationEnd(*parent_, i);
    …
  }
  repeater->OnTestProgramEnd(*parent_);
  return !failed;
}
TestCase* GetMutableTestCase(int i) {
    const int index = GetElementOr(test_case_indices_, i, -1);
    return index < 0 ? NULL : test_cases_[index];
  }
// 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();
  repeater->OnTestCaseStart(*this);
  impl->os_stack_trace_getter()->UponLeavingGTest();
  internal::HandleExceptionsInMethodIfSupported( this, &TestCase::RunSetUpTestCase, "SetUpTestCase()");
  const internal::TimeInMillis start = internal::GetTimeInMillis();
  for (int i = 0; i < total_test_count(); i++) {
    GetMutableTestInfo(i)->Run();
  }
  elapsed_time_ = internal::GetTimeInMillis() - start;
  impl->os_stack_trace_getter()->UponLeavingGTest();
  internal::HandleExceptionsInMethodIfSupported( this, &TestCase::RunTearDownTestCase, "TearDownTestCase()");
  repeater->OnTestCaseEnd(*this);
  impl->set_current_test_case(NULL);
}
TestInfo* TestCase::GetMutableTestInfo(int i) {
  const int index = GetElementOr(test_indices_, i, -1);
  return index < 0 ? NULL : test_info_list_[index];
}
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);
…
  // Creates the test object.
  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()) {
    test->Run(); 
  }
     …
  // Notifies the unit test event listener that a test has just finished.
  repeater->OnTestEnd(*this);
  impl->set_current_test_info(NULL);
}
void Test::Run() {
  if (!HasSameFixtureClass()) return;
  internal::UnitTestImpl* const impl = internal::GetUnitTestImpl();
  impl->os_stack_trace_getter()->UponLeavingGTest();
  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();
  internal::HandleExceptionsInMethodIfSupported( this, &Test::TearDown, "TearDown()");
}

綜上,執行流程簡圖如下:

UnitTestImpl::RunAllTests(){…}  --> void TestCase::Run() {…} --> void TestInfo::Run() {…} -->

void Test::Run() {…} --> void Test::TestBody(){…}

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章