0 x 00 GTestソースコードの呼び出しプロセスの初期プローブ
64388 ワード
文書ディレクトリ
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
、
、
等の特性を有する.異なる試験例は相互に影響せず、同じ試験例は異なる試験特例は相互に影響しない.私たちは独立性と呼んでいます.独立性に加えて、活性を失わない--1つのテストテスト特例では、異なるマクロ(ASSERT_*クラスマクロが後に実行することに影響し、EXPECT_*クラスマクロはできない)によって、後の実行に影響するかどうかを制御するGTestフレームワークは
を有し、プログラムパラメータでどのテスト例を実行するかを制御することができる.例えば、Factorialテストのみを実行したい場合、このようにプログラムを呼び出すことができる../sample1_unittest --gtest_filter=Factorial*
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