Googletest 实现简要分析

2023-11-03

借助于 Googletest 测试框架,我们只需编写测试用例代码,并定义简单的 main() 函数,编译之后并运行即可以把我们的测试用例跑起来。(更详细的内容可参考 Googletest 入门)。但 main() 函数调用 RUN_ALL_TESTS() 时,是如何找到并运行我们编写的测试用例代码的呢?本文尝试找寻 Googletest 框架背后隐藏的这些秘密。(代码分析基于 git@github.com:google/googletest.git 的 commit 2134e3fd857d952e03ce76064fad5ac6e9036104 的版本。)

从 TEST 和 TEST_F 说起

googletest/googletest/include/gtest/gtest.hTESTTEST_F 两个宏的定义如下:

// Note that we call GetTestTypeId() instead of GetTypeId<
// ::testing::Test>() here to get the type ID of testing::Test.  This
// is to work around a suspected linker bug when using Google Test as
// a framework on Mac OS X.  The bug causes GetTypeId<
// ::testing::Test>() to return different values depending on whether
// the call is from the Google Test framework itself or from user test
// code.  GetTestTypeId() is guaranteed to always return the same
// value, as it always calls GetTypeId<>() from the Google Test
// framework.
#define GTEST_TEST(test_suite_name, test_name)             \
  GTEST_TEST_(test_suite_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_suite_name, test_name) GTEST_TEST(test_suite_name, test_name)
#endif

// Defines a test that uses a test fixture.
//
// The first parameter is the name of the test fixture class, which
// also doubles as the test suite name.  The second parameter is the
// name of the test within the test suite.
//
// A test fixture class must be declared earlier.  The user should put
// the test code between braces after using this macro.  Example:
//
//   class FooTest : public testing::Test {
//    protected:
//     void SetUp() override { b_.AddElement(3); }
//
//     Foo a_;
//     Foo b_;
//   };
//
//   TEST_F(FooTest, InitializesCorrectly) {
//     EXPECT_TRUE(a_.StatusIsOK());
//   }
//
//   TEST_F(FooTest, ReturnsElementCountCorrectly) {
//     EXPECT_EQ(a_.size(), 0);
//     EXPECT_EQ(b_.size(), 1);
//   }
//
// GOOGLETEST_CM0011 DO NOT DELETE
#define TEST_F(test_fixture, test_name)\
  GTEST_TEST_(test_fixture, test_name, test_fixture, \
              ::testing::internal::GetTypeId<test_fixture>())

TESTTEST_F 两个宏最终都借助于 GTEST_TEST_ 宏完成其工作。

googletest/googletest/include/gtest/internal/gtest-internal.hGTEST_TEST_ 宏的定义如下:

// Expands to the name of the class that implements the given test.
#define GTEST_TEST_CLASS_NAME_(test_suite_name, test_name) \
  test_suite_name##_##test_name##_Test

// Helper macro for defining tests.
#define GTEST_TEST_(test_suite_name, test_name, parent_class, parent_id)      \
  class GTEST_TEST_CLASS_NAME_(test_suite_name, test_name)                    \
      : public parent_class {                                                 \
   public:                                                                    \
    GTEST_TEST_CLASS_NAME_(test_suite_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_suite_name,   \
                                                           test_name));       \
  };                                                                          \
                                                                              \
  ::testing::TestInfo* const GTEST_TEST_CLASS_NAME_(test_suite_name,          \
                                                    test_name)::test_info_ =  \
      ::testing::internal::MakeAndRegisterTestInfo(                           \
          #test_suite_name, #test_name, nullptr, nullptr,                     \
          ::testing::internal::CodeLocation(__FILE__, __LINE__), (parent_id), \
          ::testing::internal::SuiteApiResolver<                              \
              parent_class>::GetSetUpCaseOrSuite(__FILE__, __LINE__),         \
          ::testing::internal::SuiteApiResolver<                              \
              parent_class>::GetTearDownCaseOrSuite(__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()

GTEST_TEST_ 宏定义一个类,它为定义的类实现如下特性:

  • 类名:类名由测试套件名、测试用例名和字符串 Test 3 部分组成,不同部分用下划线分割。如 TEST_F(FooTest, InitializesCorrectly)TEST(FooTest, InitializesCorrectly) 定义的类名为 FooTest_InitializesCorrectly_Test
  • 父类:GTEST_TEST_ 宏定义的类继承自传给它的 parent_class 参数类。对于 TEST_F 宏而言,就是测试套件名,对于 TEST 则是 ::testing::Test 类。
  • GTEST_TEST_ 宏为它定义的类定义了一个空的默认构造函数。
  • GTEST_TEST_ 宏为它定义的类定义并初始化类型为 ::testing::TestInfo* const 的静态成员变量 test_info_,这个指针变量指向由 ::testing::internal::MakeAndRegisterTestInfo() 函数创建的 ::testing::TestInfo 类型对象。::testing::internal::MakeAndRegisterTestInfo() 函数还会将测试用例的信息注册给 Google Test
  • GTEST_TEST_ 宏为它定义的类定义 TestBody() 虚函数覆盖父类的对应函数,函数的函数体正是我们编写的测试用例代码,这也就是为什么我们在测试用例代码体中打断点时,看到调用栈,代码是位于名为 TestBody() 的函数中的原因。
  • 通过宏 GTEST_DISALLOW_COPY_AND_ASSIGN_ 实现类对象的禁用拷贝构造和赋值。

::testing::internal::MakeAndRegisterTestInfo() 函数定义(googletest/googletest/src/gtest.cc)如下:

// 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;
}

测试用例的注册

在通过 TESTTEST_F 宏定义测试用例时,这些宏实际上将会为测试用例定义一个类,这个类包含一个静态成员变量,在这个静态成员变量初始化时,在 ::testing::internal::MakeAndRegisterTestInfo() 函数中向 Google Test 注册测试用例,具体而言,通过 ::testing::internal::UnitTestImpl::AddTestInfo() 函数注册测试用例,该函数在 googletest/googletest/src/gtest-internal-inl.h 中定义,定义如下:

  // Adds a TestInfo to the unit test.
  //
  // Arguments:
  //
  //   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
  //   test_info:    the TestInfo object
  void AddTestInfo(internal::SetUpTestSuiteFunc set_up_tc,
                   internal::TearDownTestSuiteFunc tear_down_tc,
                   TestInfo* test_info) {
    // In order to support thread-safe death tests, we need to
    // remember the original working directory when the test program
    // was first invoked.  We cannot do this in RUN_ALL_TESTS(), as
    // the user may have changed the current directory before calling
    // RUN_ALL_TESTS().  Therefore we capture the current directory in
    // AddTestInfo(), which is called to register a TEST or TEST_F
    // before main() is reached.
    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);
  }

::testing::internal::UnitTestImpl::AddTestInfo() 函数根据测试套件名字等参数获得测试套件;然后将测试用例添加进测试套件中。

googletest/googletest/src/gtest.cc 中用于获得测试套件的 ::testing::internal::UnitTestImpl::GetTestSuite() 函数定义如下:

// Finds and returns a TestSuite with the given name.  If one doesn't
// exist, creates one and returns it.  It's the CALLER'S
// RESPONSIBILITY to ensure that this function is only called WHEN THE
// TESTS ARE NOT SHUFFLED.
//
// Arguments:
//
//   test_suite_name: name of the test suite
//   type_param:     the name of the test suite's type parameter, or NULL if
//                   this is not a typed or a type-parameterized test suite.
//   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
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;
}

::testing::internal::UnitTestImpl::GetTestSuite() 函数:

  1. 根据传入的测试套件名在测试套件 vector 中查找测试套件,如果找到就返回。
  2. 在测试套件 vector 中没有找到对应的测试套件,创建一个测试套件 TestSuite 对象。
  3. 测试套件名字与 death test 测试套件名规则匹配时,创建的测试套件被放在测试套件 vector 的前面,并在执行时先执行。
  4. 测试套件名字与 death test 测试套件名规则不匹配时,创建的测试套件被放在测试套件 vector 的后面,并在执行时后执行。

TestSuite 添加测试用例的 TestSuite::AddTestInfo() 函数定义(googletest/googletest/src/gtest.cc)如下:

// 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()));
}

测试用例的执行

main() 函数中,通过调用 testing::InitGoogleTest(&argc, argv)RUN_ALL_TESTS() 执行所有的测试用例。testing::InitGoogleTest(&argc, argv) 主要用于解析命令行参数,如 filter 等,这里不再详细分析。googletest/googletest/include/gtest/gtest.h 中的 RUN_ALL_TESTS() 函数定义如下:

// Use this function in main() to run all tests.  It returns 0 if all
// tests are successful, or 1 otherwise.
//
// RUN_ALL_TESTS() should be invoked after the command line has been
// parsed by InitGoogleTest().
//
// This function was formerly a macro; thus, it is in the global
// namespace and has an all-caps name.
int RUN_ALL_TESTS() GTEST_MUST_USE_RESULT_;

inline int RUN_ALL_TESTS() {
  return ::testing::UnitTest::GetInstance()->Run();
}

RUN_ALL_TESTS() 函数调用 googletest/googletest/src/gtest.cc 中定义的 UnitTest::Run() 函数执行所有的测试用例:

// Runs all tests in this UnitTest object and prints the result.
// Returns 0 if successful, or 1 otherwise.
//
// We don't protect this under mutex_, as we only support calling it
// from the main thread.
int UnitTest::Run() {
  const bool in_death_test_child_process =
      internal::GTEST_FLAG(internal_run_death_test).length() > 0;

  // Google Test implements this protocol for catching that a test
  // program exits before returning control to Google Test:
  //
  //   1. Upon start, Google Test creates a file whose absolute path
  //      is specified by the environment variable
  //      TEST_PREMATURE_EXIT_FILE.
  //   2. When Google Test has finished its work, it deletes the file.
  //
  // This allows a test runner to set TEST_PREMATURE_EXIT_FILE before
  // running a Google-Test-based test program and check the existence
  // of the file at the end of the test execution to see if it has
  // exited prematurely.

  // If we are in the child process of a death test, don't
  // create/delete the premature exit file, as doing so is unnecessary
  // and will confuse the parent process.  Otherwise, create/delete
  // the file upon entering/leaving this function.  If the program
  // somehow exits before this function has a chance to return, the
  // premature-exit file will be left undeleted, causing a test runner
  // that understands the premature-exit-file protocol to report the
  // test as having failed.
  const internal::ScopedPrematureExitFile premature_exit_file(
      in_death_test_child_process
          ? nullptr
          : internal::posix::GetEnv("TEST_PREMATURE_EXIT_FILE"));

  // Captures the value of GTEST_FLAG(catch_exceptions).  This value will be
  // used for the duration of the program.
  impl()->set_catch_exceptions(GTEST_FLAG(catch_exceptions));

#if GTEST_OS_WINDOWS
  // Either the user wants Google Test to catch exceptions thrown by the
  // tests or this is executing in the context of death test child
  // process. In either case the user does not want to see pop-up dialogs
  // about crashes - they are expected.
  if (impl()->catch_exceptions() || in_death_test_child_process) {
# if !GTEST_OS_WINDOWS_MOBILE && !GTEST_OS_WINDOWS_PHONE && !GTEST_OS_WINDOWS_RT
    // SetErrorMode doesn't exist on CE.
    SetErrorMode(SEM_FAILCRITICALERRORS | SEM_NOALIGNMENTFAULTEXCEPT |
                 SEM_NOGPFAULTERRORBOX | SEM_NOOPENFILEERRORBOX);
# endif  // !GTEST_OS_WINDOWS_MOBILE

# if (defined(_MSC_VER) || GTEST_OS_WINDOWS_MINGW) && !GTEST_OS_WINDOWS_MOBILE
    // Death test children can be terminated with _abort().  On Windows,
    // _abort() can show a dialog with a warning message.  This forces the
    // abort message to go to stderr instead.
    _set_error_mode(_OUT_TO_STDERR);
# endif

# if defined(_MSC_VER) && !GTEST_OS_WINDOWS_MOBILE
    // In the debug version, Visual Studio pops up a separate dialog
    // offering a choice to debug the aborted program. We need to suppress
    // this dialog or it will pop up for every EXPECT/ASSERT_DEATH statement
    // executed. Google Test will notify the user of any unexpected
    // failure via stderr.
    if (!GTEST_FLAG(break_on_failure))
      _set_abort_behavior(
          0x0,                                    // Clear the following flags:
          _WRITE_ABORT_MSG | _CALL_REPORTFAULT);  // pop-up window, core dump.
# endif
  }
#endif  // GTEST_OS_WINDOWS

  return internal::HandleExceptionsInMethodIfSupported(
      impl(),
      &internal::UnitTestImpl::RunAllTests,
      "auxiliary test code (environments or event listeners)") ? 0 : 1;
}

internal::HandleExceptionsInMethodIfSupported() 是 Google test 定义的一个用于执行类的成员函数的函数,这里不再详细分析这个函数的实现。UnitTest::Run() 函数实际上通过 googletest/googletest/src/gtest.cc 中定义的 internal::UnitTestImpl::RunAllTests() 函数执行所有的测试用例:

// Runs all tests in this UnitTest object, prints the result, and
// returns true if all tests are successful.  If any exception is
// thrown during a test, the test is considered to be failed, but the
// rest of the tests will still be run.
//
// When parameterized tests are enabled, it expands and registers
// parameterized tests first in RegisterParameterizedTests().
// All other functions called from RunAllTests() may safely assume that
// parameterized tests are ready to be counted and run.
bool UnitTestImpl::RunAllTests() {
  // True iff Google Test is initialized before RUN_ALL_TESTS() is called.
  const bool gtest_is_initialized_before_run_all_tests = GTestIsInitialized();

  // 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();

  // True iff we are in a subprocess for running a thread-safe-style
  // death test.
  bool in_subprocess_for_death_test = false;

#if GTEST_HAS_DEATH_TEST
  in_subprocess_for_death_test =
      (internal_run_death_test_flag_.get() != nullptr);
# if defined(GTEST_EXTRA_DEATH_TEST_CHILD_SETUP_)
  if (in_subprocess_for_death_test) {
    GTEST_EXTRA_DEATH_TEST_CHILD_SETUP_();
  }
# endif  // defined(GTEST_EXTRA_DEATH_TEST_CHILD_SETUP_)
#endif  // GTEST_HAS_DEATH_TEST

  const bool should_shard = ShouldShard(kTestTotalShards, kTestShardIndex,
                                        in_subprocess_for_death_test);

  // Compares the full test names with the filter to decide which
  // tests to run.
  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)) {
    // This must be called *after* FilterTests() has been called.
    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();
  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 gtest_repeat_forever = repeat < 0;
  for (int i = 0; gtest_repeat_forever || i != repeat; i++) {
    // We want to preserve failures generated by ad-hoc test
    // assertions executed before RUN_ALL_TESTS().
    ClearNonAdHocTestResult();

    const TimeInMillis start = GetTimeInMillis();

    // Shuffles test suites and tests if requested.
    if (has_tests_to_run && GTEST_FLAG(shuffle)) {
      random()->Reseed(static_cast<UInt32>(random_seed_));
      // This should be done before calling OnTestIterationStart(),
      // such that a test event listener can see the actual test order
      // in the event.
      ShuffleTests();
    }

    // Tells the unit test event listeners that the tests are about to start.
    repeater->OnTestIterationStart(*parent_, i);

    // Runs each test suite 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 or skip triggered
      // during global set-up.
      if (Test::IsSkipped()) {
        // Emit diagnostics when global set-up calls skip, as it will not be
        // emitted by default.
        TestResult& test_result =
            *internal::GetUnitTestImpl()->current_test_result();
        for (int j = 0; j < test_result.total_part_count(); ++j) {
          const TestPartResult& test_part_result =
              test_result.GetTestPartResult(j);
          if (test_part_result.type() == TestPartResult::kSkip) {
            const std::string& result = test_part_result.message();
            printf("%s\n", result.c_str());
          }
        }
        fflush(stdout);
      } else if (!Test::HasFatalFailure()) {
        for (int test_index = 0; test_index < total_test_suite_count();
             test_index++) {
          GetMutableSuiteCase(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;
    }

    // Restores the original test order after the iteration.  This
    // allows the user to quickly repro a failure that happens in the
    // N-th iteration without repeating the first (N - 1) iterations.
    // This is not enclosed in "if (GTEST_FLAG(shuffle)) { ... }", in
    // case the user somehow changes the value of the flag somewhere
    // (it's always safe to unshuffle the tests).
    UnshuffleTests();

    if (GTEST_FLAG(shuffle)) {
      // Picks a new random seed for each iteration.
      random_seed_ = GetNextRandomSeed(random_seed_);
    }
  }

  repeater->OnTestProgramEnd(*parent_);

  if (!gtest_is_initialized_before_run_all_tests) {
    ColoredPrintf(
        COLOR_RED,
        "\nIMPORTANT NOTICE - DO NOT IGNORE:\n"
        "This test program did NOT call " GTEST_INIT_GOOGLE_TEST_NAME_
        "() before calling RUN_ALL_TESTS(). This is INVALID. Soon " GTEST_NAME_
        " will start to enforce the valid usage. "
        "Please fix it ASAP, or IT WILL START TO FAIL.\n");  // NOLINT
#if GTEST_FOR_GOOGLE_
    ColoredPrintf(COLOR_RED,
                  "For more details, see http://wiki/Main/ValidGUnitMain.\n");
#endif  // GTEST_FOR_GOOGLE_
  }

  return !failed;
}

internal::UnitTestImpl::RunAllTests() 函数通过 internal::UnitTestImpl::GetMutableSuiteCase() 函数拿到测试套件 TestSuite 并执行其 Run() 函数:

void TestSuite::Run() {
  if (!should_run_) return;

  internal::UnitTestImpl* const impl = internal::GetUnitTestImpl();
  impl->set_current_test_suite(this);

  TestEventListener* repeater = UnitTest::GetInstance()->listeners().repeater();

  // Call both legacy and the new API
  repeater->OnTestSuiteStart(*this);
//  Legacy API is deprecated but still available
#ifndef GTEST_REMOVE_LEGACY_TEST_CASEAPI
  repeater->OnTestCaseStart(*this);
#endif  //  GTEST_REMOVE_LEGACY_TEST_CASEAPI

  impl->os_stack_trace_getter()->UponLeavingGTest();
  internal::HandleExceptionsInMethodIfSupported(
      this, &TestSuite::RunSetUpTestSuite, "SetUpTestSuite()");

  start_timestamp_ = internal::GetTimeInMillis();
  for (int i = 0; i < total_test_count(); i++) {
    GetMutableTestInfo(i)->Run();
  }
  elapsed_time_ = internal::GetTimeInMillis() - start_timestamp_;

  impl->os_stack_trace_getter()->UponLeavingGTest();
  internal::HandleExceptionsInMethodIfSupported(
      this, &TestSuite::RunTearDownTestSuite, "TearDownTestSuite()");

  // Call both legacy and the new API
  repeater->OnTestSuiteEnd(*this);
//  Legacy API is deprecated but still available
#ifndef GTEST_REMOVE_LEGACY_TEST_CASEAPI
  repeater->OnTestCaseEnd(*this);
#endif  //  GTEST_REMOVE_LEGACY_TEST_CASEAPI

  impl->set_current_test_suite(nullptr);
}

TestSuite::Run() 函数通过 GetMutableTestInfo() 函数获得 TestInfo 并执行其 Run() 函数,TestInfo::Run() 函数定义如下:

// Creates the test object, runs it, records its result, and then
// deletes it.
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* const test = internal::HandleExceptionsInMethodIfSupported(
      factory_, &internal::TestFactoryBase::CreateTest,
      "the test fixture's constructor");

  // Runs the test if the constructor didn't generate a fatal failure or invoke
  // GTEST_SKIP().
  // Note that the object will not be null
  if (!Test::HasFatalFailure() && !Test::IsSkipped()) {
    // This doesn't throw as all user code that can throw are wrapped into
    // exception handling code.
    test->Run();
  }

  if (test != nullptr) {
    // Deletes the test object.
    impl->os_stack_trace_getter()->UponLeavingGTest();
    internal::HandleExceptionsInMethodIfSupported(
        test, &Test::DeleteSelf_, "the test fixture's destructor");
  }

  result_.set_start_timestamp(start);
  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(nullptr);
}

TestInfo::Run() 函数创建测试用例类对象,并执行其 Run() 函数。Test::Run() 执行测试用例定义的 SetUp(),测试用例主体 TestBody() 函数,和 TearDown() 函数:

// 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();
  internal::HandleExceptionsInMethodIfSupported(this, &Test::SetUp, "SetUp()");
  // We will run the test only if SetUp() was successful and didn't call
  // GTEST_SKIP().
  if (!HasFatalFailure() && !IsSkipped()) {
    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()");
}

测试用例的调用执行过程大概是这样的:

RUN_ALL_TESTS() -> UnitTest::Run() -> UnitTestImpl::RunAllTests() -> TestSuite::Run() -> TestInfo::Run() -> Test::Run() -> Test::TestBody()

Done。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Googletest 实现简要分析 的相关文章

  • Linux内核模块管理

    模块的全称是动态可加载内核模块 它是具有独立功能的程序 可以被单独编译 但不能独立运行 模块是为内核或其他模块提供功能的代码集合 这些模块可以是 Linux 源码中自带的 也可以是由硬件厂商开发的 可以想象成驱动 安装模块一般有两种方法 第
  • ubuntu中执行脚本出现no such file or directory

    问题 在ubuntu下执行 sh文件大多数情况下只需要注意给脚本文件添加可执行权限就可以了 但是有些情况下会出现这种问题 从上图可以看到 文件夹中的几个脚本文件的权限都达到了 777 按理说任何用户都可以执行这些脚本 但是执行其中任意的就出
  • linux fdisk的分区和格式化和挂载相关操作说明

    注意 分区的时候要umount磁盘之后才能分区 在Ubuntu用fdisk分析需要root用户权限 第一步 先把设备卸载掉 解除占用 caizd ubuntu home share lsblk 查看大小空间 caizd ubuntu hom
  • openEuler 20.03 LTS SP2以及SP3安装完gnome后,gdm登陆进入不了桌面问题

    一 问题原因 是由于CVE 2020 17489相关补丁引入的 暂不清楚是何原因造成 但除去该相关补丁之后 该问题消失 在网上查了下 CVE 2020 17489的问题是gnome shell的某些配置中会发现 注销账户时 登陆对话框中的密
  • Googletest 实现简要分析

    借助于 Googletest 测试框架 我们只需编写测试用例代码 并定义简单的 main 函数 编译之后并运行即可以把我们的测试用例跑起来 更详细的内容可参考 Googletest 入门 但 main 函数调用 RUN ALL TESTS
  • SIGPIPE的设计意图

    SIGPIPE的设计意图 SIGPIPE 是为以下这种情况设计的 grep pattern lt reallyhugefile head grep可能会输出成千上万行文本 但 head 只会读取前10行然后就退出 一旦head退出 grep
  • Android/Linux EAS优化-schedtune

    Linux cgroups机制中的cpu cpuset schedtune子系统 跟linux android进程调度策略有关 记录下各项功能参数的用法 SchedTune SchedTune是一项与CPU调频相关的性能提升技术 它实现为一
  • u-boot常用命令

    u boot常用命令 查看u boot所支持的命令 查询命令 u boot版本 环境变量 板子相关信息 环境变量操作 内存操作 网络操作 EMMC和 SD卡操作 FAT 格式文件系统操作 EXT格式文件系统操作 ubi格式文件系统操作 bo
  • ubuntu+vscode构建c++开发调试环境

    1 vscode下载与安装 下载 Visual Studio Code Mac Linux Windows下载deb文件 运行指令安装vscode sudo dpkg i xxx deb 如果报 dpkg 错误 另外一个进程已经为 dpkg
  • 网络编程之三

    代码1 chat tcp client1 c include header h int main int argc char argv int connfd 1 if 0 gt connfd socket AF INET SOCK STRE
  • Linux下的时间(ZZ)

    1 Linux下的时间 1 1 Linux下的时间系统 1 2 Linux下与时间有关的数据结构 2 获得当前时间 3 延时 4 定时器 4 1 alarm 4 2 setitimer 1 Linux下的时间1 1 Linux下的时间系统
  • Ubuntu搭建Nginx服务器

    Ubuntu搭建Nginx服务器 安装Nginx 配置文件 全局配置文件 子配置文件管理 sites availables和sites enabled default配置文件 启动 停止 重启Nginx 启动 停止 重启 查询 其他设置 自
  • valgrind 在开发板上运行以及使用

    前言 bedug无处不在 今天花落我家 现象 一个月出现一次异常 难易复现排查 借助神器valgrind排查 1 下载及编译准备 下载地址 https www valgrind org tar jxvf valgrind 3 16 1 ta
  • Linux的c编程-文件节点的打开与读写操作

    1 open 打开文件 相关函数 read write fcntl close link stat umask unlink fopen 表头文件 include
  • /sys/module 模块信息与 /proc/modules

    看到一篇关于 proc moduels 以及 sys module 相关介绍 转载一下 http linux chinaunix net techdoc system 2008 07 18 1018163 shtml 在编译模块的时候 如果
  • Linux学习笔记(九) -- 利用Code::Blocks建立C++静态链接库

    1 测试平台 测试平台 Linux版本 Ubuntu 18 04 LTS Code Blocks版本 16 01 2 操作步骤 2 1 启动Code Blocks 2 2 新建静态链接库工程 1 选择 File 菜单中的 New Proje
  • Ubuntu(20.04):设置DNS

    编辑文件 etc systemd resolved conf 设置DNS 8 8 8 8 114 114 114 114 保存退出后 以sudo身份运行 systemctl restart systemd resolved systemct
  • Ubuntu下安装和注册beyond compare 4

    下载 安装 下载安装包网址 Ubuntu上选择Debian安装包 https www scootersoftware com download php sudo dpkg i bcompare 4 4 6 27483 amd64 deb 注
  • 通过进入单用户模式解决linux中的rc.local修改后无法启动的问题

    问题 本想将teamviewer这个软件随linux自启动 所以将其启动命令放在rc local中 但是重启后发现linux启动不起来了 系统前面都是正常启动的 就是无法进入帐户登陆界面 无法输入root帐号密码 不能登陆到系统 按了ctr
  • linux 复位usb设备 模拟热插拔脚本

    获取USB设备数量 DEVICE NUM lspci grep USB awk F print 1 wc l 获取设备号 DEVICE lspci grep USB awk F print 0000 1 sed n i p 设备解绑 ech

随机推荐

  • 什么是布隆过滤器?——超详细解析【建议收藏】

    目录 1 什么是布隆过滤器 2 实现原理 2 1 回顾哈希函数 2 1 1 哈希函数概念 2 1 2 散列函数的基本特性 2 2 布隆过滤器数据结构 3 特点 3 1 支持删除吗 3 2 优点 3 3 缺点 3 4 误判率 4 如何选择哈希
  • C++错误:不允许使用不完整的类型

    写了下面这个代码 结果在ifstream处提示 不允许使用不完整的类型 string from to cin gt gt from gt gt to ifstream is from c str istream iterator
  • Logo制作

    详细制作过程 下载安装Inkscape 绘制基本的图形 1 下载安装inkspace 打开 文件 新建一个文档 2 选择绘制图形 3 然后添加图形 选择自己想要的效果 4 最后效果如下
  • java.lang.NullPointerException (no error message)问题解决

    问题描述 Android Studio项目同步时报错 java lang NullPointerException no error message 问题原因 有人说是 Android Gradle Plugin Version Gradl
  • java之暴力反射,执行私有方法

    废话少说 直接show code import java lang reflect InvocationTargetException import java lang reflect Method 暴力反射 public class Te
  • Unity3D 原生WebCamera实现摄像头显示

    Unity3D 原生WebCamera实现摄像头显示 今天小编为大家分享一下 如何通过WebCamera 调用外部的摄像头 1 首先我们需要简单认识一下 unity有关摄像头需要用到的内置类 WebCamDevice 官方文档 https
  • Rsync 12种故障排查及思路

    Rsync 故障排查整理 Rsync服务常见问题汇总讲解 1 客户端的错误现象 No route to host rsync服务端开启的iptables防火墙 root nfs01 tmp rsync avz etc hosts rsync
  • Mybatis-Plus eq、ne、gt、lt、ge、le分别代表含义

    Mybatis Plus eq ne gt lt ge le分别代表含义 eq 就是 equal等于 ne就是 not equal不等于 gt 就是 greater than大于 lt 就是 less than小于 ge 就是 greate
  • 关于burp suite安装无法抓包问题(火狐)

    刚进该领域的纯小白一个 按照网上的教程一步步都搞好了 包括CA证书 Java jdk1 8版本等 但是就是弄不好 代理调整好后访问百度网址显示 建立安全连接失败 一开始我以为他就该这样 但是发现burp suite无法抓包 按照提示先点击拦
  • Elasticsearch 基本使用(五)查询条件匹配方式(query & query_string)

    查询条件匹配方式 概述 query term terms range match all match match 匹配精度问题 match phrase match pharse prefix match bool prefix multi
  • 21天Jenkins打卡day8-配置SSH远程服务器

    参考文档 http istester com jenkins 427 html
  • 使用 ipmi实现Linux系统下对服务器的管理

    IPMI Intelligent Platform Management Interface 即智能平台管理接口是使硬件管理具备 智能化 的新一代通用接口标准 用户可以利用 IPMI 监视服务器的物理特征 如温度 电压 电扇工作状态 电源供
  • 【Linux网络】网络编程套接字(上)

    Linux 博客主页 一起去看日落吗 分享博主的在Linux中学习到的知识和遇到的问题 博主的能力有限 出现错误希望大家不吝赐教 分享给大家一句我很喜欢的话 看似不起波澜的日复一日 一定会在某一天让你看见坚持的意义 祝我们都能在鸡零狗碎里找
  • ospf协议_三级网络技术考前选择题3—OSPF协议

    一 视频讲解 二 知识点背诵 高频21次 1 OSPF是内部网关协议的一种 采用最短路径算法 使用分布式链路状态协议 2 对于规模很大的网络 OSPF通过划分区域来提高路由更新收敛速度 每个区域有一个32位的区域标识符 区域内路由器不超过2
  • Springboot+Shiro+Jwt实现简单的权限控制

    前置背景 为什么写下这篇文章 因为需要实现一个设备管理系统的权限管理模块 在查阅很多博客以及其他网上资料之后 发现重复 无用的博客很多 因此写一篇文章来记录 以便后面复习 涉及的知识点主要有下列知识点 JWT shiro 书写顺序 首先使用
  • 本地写json数据并在页面中调用

    这里我自己写的是两个方法 一种是用js文件中写的 一种是在json文件中写的 js文件 var workData firstWork companyName time department position project name tim
  • 好文

    https www jianshu com p c2ec5f06cf1a
  • 带隙基准电流源设计与改进/自己备忘

    采用1830工艺设计 预设值电流I 10uA 由公式 过驱动电压0 2V 得到PMOS宽长比12 5 1 由公式 过驱动电压0 2V 得到NM8宽长比2 8 1 设置K 4 NM7宽长比4 2 8 1 由公式 带入计算得到R大小为9 96K
  • [1197]脱壳工具dumpDex的使用详解

    文章目录 一 dumpDex概述 二 使用方法 三 脱壳原理 一 dumpDex概述 dumpDex 一个开源的 Android 脱壳插件工具 需要xposed支持 可以用来脱掉当前市场上大部分的壳 360加固 腾讯乐固 梆梆加固 百度加固
  • Googletest 实现简要分析

    借助于 Googletest 测试框架 我们只需编写测试用例代码 并定义简单的 main 函数 编译之后并运行即可以把我们的测试用例跑起来 更详细的内容可参考 Googletest 入门 但 main 函数调用 RUN ALL TESTS