0 x 00 GTestソースコードの呼び出しプロセスの初期プローブ


文書ディレクトリ

  • gtest総観
  • TESTマクロ実装
  • 試験用例スケジューリングメカニズム実現
  • gtest総観

  • 試験用例名および試験特例名については、下線()は使用できません.GTestソースコードでは、下線を使用して独立したクラス名
  • に接続する必要があるためです.
    // Expands to the name of the class that implements the given test.
    #define GTEST_TEST_CLASS_NAME_(test_case_name, test_name) \
        test_case_name##_##test_name##_Test
    
  • GTestは 等の特性を有する.異なる試験例は相互に影響せず、同じ試験例は異なる試験特例は相互に影響しない.私たちは独立性と呼んでいます.独立性に加えて、活性を失わない--1つのテストテスト特例では、異なるマクロ(ASSERT_*クラスマクロが後に実行することに影響し、EXPECT_*クラスマクロはできない)によって、後の実行に影響するかどうかを制御するGTestフレームワークは を有し、プログラムパラメータでどのテスト例を実行するかを制御することができる.例えば、Factorialテストのみを実行したい場合、このようにプログラムを呼び出すことができる.
  • ./sample1_unittest --gtest_filter=Factorial*
    
  • 私たちのテストを前に処理すると、複雑なデータを構築することがよくあります.各テスト特例でデータを構築する場合は、非常に煩雑で美しくありません.GTestは、データを事前に構築する方法を提供しています.次のコードを例に
  • class ListTest : public testing::Test {
     protected:
      virtual void SetUp() {
    	  _m_list[0] = 11;
    	  _m_list[1] = 12;
    	  _m_list[2] = 13;
      }
      int _m_list[3];
    };
    TEST_F(ListTest, FirstElement) {
      EXPECT_EQ(11, _m_list[0]);
    }
     
    TEST_F(ListTest, SecondElement) {
      EXPECT_EQ(12, _m_list[1]);
    }
     
    TEST_F(ListTest, ThirdElement) {
      EXPECT_EQ(13, _m_list[2]);
    }
    

    ListTestクラスをGTestが提供するベースクラスtesting::Testに継承し、SetUpメソッドを再ロードします.これにより、ListTestのテスト例外を実行するたびに、SetUpメソッドが1回実行され、データの準備が完了します.これにより、1つのクラスでデータを構築すればいいです.ここで注意が必要だFマクロ、その第1のパラメータはクラス名、すなわちListTesであることが要求される.TESTマクロの最初のパラメータとは違って、私たちは勝手に名前を付けることができます.

    TESTマクロ実装


    TESTはgtestにある.h line2311
    #define GTEST_TEST(test_case_name, test_name)\
      GTEST_TEST_(test_case_name, test_name, \
                  ::testing::Test, ::testing::internal::GetTestTypeId())
     
    // Define this macro to 1 to omit the definition of TEST(), which
    // is a generic name and clashes with some other libraries.
    #if !GTEST_DONT_DEFINE_TEST
    # define TEST(test_case_name, test_name) GTEST_TEST(test_case_name, test_name)
    

    GTEST_TEST_gtest-internalに位置する.h line1402
    #define GTEST_TEST_(test_suit_name, test_name, parent_class, paremt_id)\
    class GTEST_TEST_CLASS_NAME_(test_suit_name, test_name)\
        : public parent_class{ \
    public:
        GTEST_TEST_CLASS_NAME_(test_suit_name, test_name)(){}
        
    private:
        virtual void TestBody();
        static ::testing::TestInfo* const test_info_ GTEST_ATTRIBUTE_UNUSED_;
        GTEST_DISALLOW_COPY_AND_ASSIGN_(GTEST_TEST_CLASS_NAME_(test_suit_name, test_name));
    };
    
    
    ::testing::TestInfo* const GTEST_TEST_CLASS_NAME_(test_suit_name, test_name)::test_info_ = 
        ::testing::internal::MakeAndRegisterTestInfo(
        #test_suit_name, #test_name, nullptr, nullptr,
        ::testing::internal::CodeLocation(__FILE__, __LINE__), (parent_id),
        ::testing::internal::SuitApiResolver<
            parent_class>::GetSetUpCaseOrSuite(__FILE, __LINE__),
        ::testing::internal::SuitApiResolver<
            parent_class>::GetSetDownCaseOrSuite(__FILE, __LINE__),
        new ::testing::internal::TestFactoryImpl<GTEST_TEST_CLASS_NAME_(
        test_suite_name, test_name)>);
    void GTEST_TEST_CLASS_NAME_(test_suite_name, test_name)::TestBody()
     
    

    test_info_ 初期化
    // Creates a new TestInfo object and registers it with Google Test;
    // returns the created object.
    //
    // Arguments:
    //
    //   test_suite_name:   name of the test suite
    //   name:             name of the test
    //   type_param:       the name of the test's type parameter, or NULL if
    //                     this is not a typed or a type-parameterized test.
    //   value_param:      text representation of the test's value parameter,
    //                     or NULL if this is not a value-parameterized test.
    //   code_location:    code location where the test is defined
    //   fixture_class_id: ID of the test fixture class
    //   set_up_tc:        pointer to the function that sets up the test suite
    //   tear_down_tc:     pointer to the function that tears down the test suite
    //   factory:          pointer to the factory that creates a test object.
    //                     The newly created TestInfo instance will assume
    //                     ownership of the factory object.
    TestInfo* MakeAndRegisterTestInfo(
        const char* test_suite_name, const char* name, const char* type_param,
        const char* value_param, CodeLocation code_location,
        TypeId fixture_class_id, SetUpTestSuiteFunc set_up_tc,
        TearDownTestSuiteFunc tear_down_tc, TestFactoryBase* factory) {
      TestInfo* const test_info =
          new TestInfo(test_suite_name, name, type_param, value_param,
                       code_location, fixture_class_id, factory);
      GetUnitTestImpl()->AddTestInfo(set_up_tc, tear_down_tc, test_info);
      return test_info;
    }
    
    
    // 1. CodeLocation
    struct CodeLocation {
      CodeLocation(const std::string& a_file, int a_line)
        : file(a_file)
        , line(a_line)
      {
          
      }
        
        std::string file;
        int line;
    }
    
    
    // 2. ::testing::internal::GetTestTypeId()
    typedef const void* TypeId;
    template<typename T>
    class TypeIdHelper
    {
    public:
        static bool dummy_;
    };
    
    template<typename T>
    bool TypeIdHelper<T>::dummy_ = false;
    
    // TEST_F 
    template<typename T>
    TypeId GetTypeId(){
        return &(TypeIdHelper<T>::dummy_);
    }
    
    // TEST
    TypeId GetTypeId(){
        return GetTypeId<Test>();
    }
    
    
    // 3. SetUpTestSuiteFunc set_up_tc
    // 4. TearDownTestSuiteFunc tear_down_tc
    
    //  Helper to identify which setup function for TestCase / TestSuite to call.
    //  Only one function is allowed, either TestCase or TestSute but not both.
    
    // Utility functions to help SuiteApiResolver
    using SetUpTearDownSuiteFuncType = void (*)();
    
    inline SetUpTearDownSuiteFuncType GetNotDefaultOrNull(
        SetUpTearDownSuiteFuncType a, SetUpTearDownSuiteFuncType def) {
      return a == def ? nullptr : a;
    }
    
    template <typename T>
    //  Note that SuiteApiResolver inherits from T because
    //  SetUpTestSuite()/TearDownTestSuite() could be protected. Ths way
    //  SuiteApiResolver can access them.
    struct SuiteApiResolver : T {
      // testing::Test is only forward declared at this point. So we make it a
      // dependend class for the compiler to be OK with it.
      using Test =
          typename std::conditional<sizeof(T) != 0, ::testing::Test, void>::type;
    
      static SetUpTearDownSuiteFuncType GetSetUpCaseOrSuite(const char* filename,
                                                            int line_num) {
    #ifndef GTEST_REMOVE_LEGACY_TEST_CASEAPI_
        SetUpTearDownSuiteFuncType test_case_fp =
            GetNotDefaultOrNull(&T::SetUpTestCase, &Test::SetUpTestCase);
        SetUpTearDownSuiteFuncType test_suite_fp =
            GetNotDefaultOrNull(&T::SetUpTestSuite, &Test::SetUpTestSuite);
    
        GTEST_CHECK_(!test_case_fp || !test_suite_fp)
            << "Test can not provide both SetUpTestSuite and SetUpTestCase, please "
               "make sure there is only one present at "
            << filename << ":" << line_num;
    
        return test_case_fp != nullptr ? test_case_fp : test_suite_fp;
    #else
        (void)(filename);
        (void)(line_num);
        return &T::SetUpTestSuite;
    #endif
      }
    
      static SetUpTearDownSuiteFuncType GetTearDownCaseOrSuite(const char* filename,
                                                               int line_num) {
    #ifndef GTEST_REMOVE_LEGACY_TEST_CASEAPI_
        SetUpTearDownSuiteFuncType test_case_fp =
            GetNotDefaultOrNull(&T::TearDownTestCase, &Test::TearDownTestCase);
        SetUpTearDownSuiteFuncType test_suite_fp =
            GetNotDefaultOrNull(&T::TearDownTestSuite, &Test::TearDownTestSuite);
    
        GTEST_CHECK_(!test_case_fp || !test_suite_fp)
            << "Test can not provide both TearDownTestSuite and TearDownTestCase,"
               " please make sure there is only one present at"
            << filename << ":" << line_num;
    
        return test_case_fp != nullptr ? test_case_fp : test_suite_fp;
    #else
        (void)(filename);
        (void)(line_num);
        return &T::TearDownTestSuite;
    #endif
      }
    };
    
    // 5. TestFactoryBase* factory
    // new ::testing::internal::TestFactoryImpl
    //  test_suite_name, test_name)>
    
    class TestFactoryBase {
     public:
      virtual ~TestFactoryBase() {}
    
      // Creates a test instance to run. The instance is both created and destroyed
      // within TestInfoImpl::Run()
      virtual Test* CreateTest() = 0;
    
     protected:
      TestFactoryBase() {}
    
     private:
      GTEST_DISALLOW_COPY_AND_ASSIGN_(TestFactoryBase);
    };
    
    // This class provides implementation of TeastFactoryBase interface.
    // It is used in TEST and TEST_F macros.
    template <class TestClass>
    class TestFactoryImpl : public TestFactoryBase {
     public:
      Test* CreateTest() override { return new TestClass; }
    };
    
    // trick
    #define GTEST_DISALLOW_COPY_AND_ASSIGN_(type) \
     type(type const &) = delete; \
     GTEST_DISALLOW_ASSIGN_(type)
     
    #define GTEST_DISALLOW_ASSIGN_(type) \
     void operator=(type const &) = delete
     
    // 6. GetUnitTestImpl
    inline UnitTestImpl* GetUnitTestImpl()
    {
        return UnitTest::GetInstance()->impl();
    }
    
    //gtest-internal-inl.h
    void AddTestInfo(internal::SetUpTestSuiteFunc set_up_tc,
                       internal::TearDownTestSuiteFunc tear_down_tc,
                       TestInfo* test_info) {
        if (original_working_dir_.IsEmpty()) {
          original_working_dir_.Set(FilePath::GetCurrentDir());
          GTEST_CHECK_(!original_working_dir_.IsEmpty())
              << "Failed to get the current working directory.";
        }
    
        GetTestSuite(test_info->test_suite_name(), test_info->type_param(),
                     set_up_tc, tear_down_tc)
            ->AddTestInfo(test_info);
    }
    
    //  , TestCase , test_suites_ 
    TestSuite* UnitTestImpl::GetTestSuite(
        const char* test_suite_name, const char* type_param,
        internal::SetUpTestSuiteFunc set_up_tc,
        internal::TearDownTestSuiteFunc tear_down_tc) {
      // Can we find a TestSuite with the given name?
      const auto test_suite =
          std::find_if(test_suites_.rbegin(), test_suites_.rend(),
                       TestSuiteNameIs(test_suite_name));
    
      if (test_suite != test_suites_.rend()) return *test_suite;
    
      // No.  Let's create one.
      auto* const new_test_suite =
          new TestSuite(test_suite_name, type_param, set_up_tc, tear_down_tc);
    
      // Is this a death test suite?
      if (internal::UnitTestOptions::MatchesFilter(test_suite_name,
                                                   kDeathTestSuiteFilter)) {
        // Yes.  Inserts the test suite after the last death test suite
        // defined so far.  This only works when the test suites haven't
        // been shuffled.  Otherwise we may end up running a death test
        // after a non-death test.
        ++last_death_test_suite_;
        test_suites_.insert(test_suites_.begin() + last_death_test_suite_,
                            new_test_suite);
      } else {
        // No.  Appends to the end of the list.
        test_suites_.push_back(new_test_suite);
      }
    
      test_suite_indices_.push_back(static_cast<int>(test_suite_indices_.size()));
      return new_test_suite;
    }
    
    
    // Adds a test to this test suite.  Will delete the test upon
    // destruction of the TestSuite object.
    void TestSuite::AddTestInfo(TestInfo* test_info) {
      test_info_list_.push_back(test_info);
      test_indices_.push_back(static_cast<int>(test_indices_.size()));
    }
    
    

    テストケーススケジューリングメカニズムの実装

    // gtest_main.cc
    GTEST_API_ int main(int argc, char **argv) {
      printf("Running main() from gtest_main.cc
    "
    ); testing::InitGoogleTest(&argc, argv); return RUN_ALL_TESTS(); } inline int RUN_ALL_TESTS() { return ::testing::UnitTest::GetInstance()->Run(); } 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 HandleSehExceptionsInMethodIfSupported(object, method, location); } // --> 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( // NOLINT GetExceptionCode())) { // We create the exception message on the heap because VC++ prohibits // creation of objects with destructors on stack in functions using __try // (see error C2712). 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 } // impl() -> &internal::UnitTestImpl::RunAllTests { // ,gtest.cc for (int test_index = 0; test_index < total_test_suite_count(); test_index++) { GetMutableSuiteCase(test_index)->Run(); if (GTEST_FLAG(fail_fast) && GetMutableSuiteCase(test_index)->Failed()) { for (int j = test_index + 1; j < total_test_suite_count(); j++) { GetMutableSuiteCase(j)->Skip(); } break; } } } // Gets the i-th test suite among all the test suites. i can range from 0 to // total_test_suite_count() - 1. If i is not in that range, returns NULL. // file: gtest-internal-inl.h TestSuite* GetMutableSuiteCase(int i) { const int index = GetElementOr(test_suite_indices_, i, -1); return index < 0 ? nullptr : test_suites_[static_cast<size_t>(index)]; } // TestSuite for (int i = 0; i < total_test_count(), i++) { GetMutableTestInfo(i)->Run(); } TestInfo* GetMutableTestInfo(int i) { const int index = GetElementOr(test_indices_, i, -1); return index < 0 ? nullptr : test_info_list_[static_cast<size_t>(index)]; } // TestInfo void TestInfo::Run() { // ... Test* const test = internal::HandleExceptionsInMethodIfSupported( factory_, &internal::TestFactoryBase::CreateTest, "the test fixture's constructor"); // ... if ((test != NULL) && !Test::HasFatalFailure()) { test->Run(); } } // Test Run void Test::Run() { // ... if (!HasFatalFailure() && !IsSkipped()) { //.. internal::HandleExceptionsInMethodIfSupported( this, &Test::TesBody, "the test body"); } } // Test Run , Test Run TestBody