Google Test源码浅析(二) -------- TEST宏

一、TEST宏的定义

一个例子:

TEST(TestCaseName1, TestName1){                                                                                                  
      cout << "hello1" << endl;                                                                                                    
 }                                                                                                                                

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

  宏的替换本质上是文本的替换,在预处理阶段就已经完成,故我们在linux下可以看到预处理阶段所完成的事情
  

//表明这是一个以test_case_name和test_name拼接起来的类
//同时继承继而父类Test
//一个执行编写测试用例的逻辑
//一个静态成员test_info_,主要用于注册测试用例信息
//不能拷贝和赋值
class TestCaseName1_TestName1_Test : public ::testing::Test                                                                    
{                                                                                                                              
   public:                                                                                                                      
     TestCaseName1_TestName1_Test()                                                                                             
     {}                                                                                                                         
   private:                                                                                                                     
     virtual void TestBody();                                                                                                   
     static ::testing::TestInfo* const test_info_ __attribute__ ((unused));                                                                                                     
     TestCaseName1_TestName1_Test(TestCaseName1_TestName1_Test const &);                                                        
     void operator=(TestCaseName1_TestName1_Test const &);                                                                      
 };                                                                                                                             

    //静态成员的初始化                                                                                                                        
    ::testing::TestInfo* const TestCaseName1_TestName1_Test ::test_info_ =                                                         
    ::testing::internal::MakeAndRegisterTestInfo(//注册信息后面解释                                                                                  
     "TestCaseName1", "TestName1", __null, __null,                                                                              
    ::testing::internal::CodeLocation("test1.cc", 6),//快速定位(::testing::internal::GetTestTypeId()),  //生成唯一id,后面解释                                
    ::testing::Test::SetUpTestCase, //初始化                                                                                   
    ::testing::Test::TearDownTestCase, //释放
       new ::testing::internal::TestFactoryImpl< TestCaseName1_TestName1_Test>);   //工厂函数,后面解释

 //执行的函数体                                                    
 void TestCaseName1_TestName1_Test::TestBody(){                                                                         
     cout << "hello1" << endl;                                                                                                  
 }      

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

二、源码

1. 生成唯一测试用例ID——— GetTestTypeId

  GetTestTypeId()的目的是为了生成一个唯一的ID,其实现原理非常简单,取类成员静态变量的地址保证唯一性。 该ID用于唯一的标识一个测试用例。

//TypeId是一个指针
typedef const void* TypeId;                                                                                                   

 template <typename T>                                                                                                         
 class TypeIdHelper {                                                                                                          
  public:                                                                                                                      
  //是一个静态成员变量,其初值为false,当生成测试用例ID时,就变为true,将此地址作为测试用例的唯一id                                          
  static bool dummy_;                                                                                                         
};   
template <typename T>                                                                                                         
    TypeId GetTypeId() {  //分配出不同的静态成员变量,这个地址是唯一的                                                                                                        
   // The compiler is required to allocate a different                                                                         
  // TypeIdHelper<T>::dummy_ variable for each T used to instantiate  the template.  Therefore, the address of dummy_ is guaranteed                                                          to be unique.                                                                                                                                                                      
    return &(TypeIdHelper<T>::dummy_);                                                                                          
 }    
 //调用时传了一个Test,这里的Test是一个范型                      
  TypeId GetTestTypeId() 
  {
      return GetTypeId<Test>();
   }    
2. 记录测试用例的位置—— CodeLocation

  通过参数将其测试用例所在的文件名称和所在的行数传递过来,后面调度测试用例的时候可以快速定位

struct CodeLocation {                                                                                                         
   CodeLocation(const string& a_file, int a_line) 
       : file(a_file), line(a_line) 
       {}                                              

  string file;   //文件名                                                                                                             
  int line;     //行号                                                                                                              
};     
3. 建立测试用例和释放测试用例
    ::testing::Test::SetUpTestCase, //初始化                                                                                   
    ::testing::Test::TearDownTestCase, //释放
4. 工厂函数———– TestFactoryImpl()

  目的是创建了一个TEST类

//只仅仅提供了一个基类
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);                                                                           
};              
//创建一个TEST的类
template <class TestClass>                                                                                                    class TestFactoryImpl : public TestFactoryBase {                                                                              
  public:                                                                                                                      
    virtual Test* CreateTest() 
    { 
    return new TestClass; 
    }                                                                        
 };       
5. 注册测试用例信息———- MakeAndRegisterTestInfo

  前面的几个接口全部包含在这个函数里面,用来做测试用例的准备工作
 
MakeAndRegisterTestInfo的代码逻辑:

  1. new 一个TestInfo类

  2. 通过GetUnitTestImpl接口获取一个UnitTestImpl单例

  3. 把TestInfo添加到UnitTestImpl单例中,即对测试用例的信息进行注册

源码:

 TestInfo* MakeAndRegisterTestInfo(//创建一个类并且注册TestInfo                                                                
      const char* test_case_name, //TEST宏的两个参数                                                                                              
      const char* name,                                                                                                       
      const char* type_param,  //主要用于TEST_P.TEST中其值为NULL                                                                                                 
      const char* value_param, //主要用于TEST_P.TEST中其值为NULL                                                                                              
      CodeLocation code_location,                                                                                              
      TypeId fixture_class_id,                                                                                               
      SetUpTestCaseFunc set_up_tc,     //主要用于TEST_F                                                                                         
      TearDownTestCaseFunc tear_down_tc,  //主要用于TEST_F                                                                                      
      TestFactoryBase* factory) {                                                                                               
     //new一个test_info实例,保存测试用例相关的信息,后续执行时添加测试结果
      TestInfo* const test_info =                                                                                                 
      new TestInfo(test_case_name, name, type_param, value_param,code_location, fixture_class_id, factory);                                                                                                                           
     GetUnitTestImpl()->AddTestInfo(set_up_tc, tear_down_tc, test_info);//将实例添加到UnitTestImpl单例中                                                         
  return test_info;                                                                                                           
 } 
6. UnitTestImpl::AddTestInfo()
  1. 从源码的注释来看,这是为了保护死亡测试的线程安全

  2. 如果当前测试用例获取不到一个Testcase类,就创建一个TestCase类

  3. 将test_info的信息添加到TestCase类中

void AddTestInfo(Test::SetUpTestCaseFunc set_up_tc,                                                                         
                   Test::TearDownTestCaseFunc 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.";                                                                  
     }                                                                                                                         

    GetTestCase(test_info->test_case_name(),                                                                                  
                test_info->type_param(),                                                                                      
                set_up_tc,                                                                                                    
                tear_down_tc)->AddTestInfo(test_info);                                                                        
   }                                  
7. UnitTestImpl::GetTestCase()

几个变量:

  1. test_cases_是一个vector,保存着所有的测试用例
  2. last_death_test_case_是vector里死亡测试数量,也是死亡测试用例的下标
  3. test_case_indices_是记录当前测试用例的数量
TestCase* UnitTestImpl::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?  将所有的TestCase保存在一个数组当中,去找有没有当前所用到的TestCase                                                                            
  const std::vector<TestCase*>::const_iterator test_case =                                                                    
      std::find_if(test_cases_.begin(), test_cases_.end(),                                                                    
                      TestCaseNameIs(test_case_name));                                                                           
    //找到返回迭代器                                                                                                                           
    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);

    // Is this a death test case? 判断当前是否为死亡测试                                                                                               
   if (internal::UnitTestOptions::MatchesFilter(test_case_name,                                                                
                                               kDeathTestCaseFilter)) {   
     //如果是死亡测试,就将其插入到最后一个死亡测试用例的后面,不是就将其插入到所有测试用例的后面  
     //当还没有被洗牌,使死亡测试最先指向,否则会先执行非死亡测试,将死亡测试放到最后在执行                                                                                            
    // Yes.  Inserts the test case after the last death test case                                                             
    // defined so far.  This only works when the test cases haven't                                                           
   // been shuffled.  Otherwise we may end up running a death test  after a non-death test.                                                                                                                                                                        
     ++last_death_test_case_;                                                                                                  
    test_cases_.insert(test_cases_.begin() + last_death_test_case_,                                                           
                       new_test_case);                                                                                        
   } else {                                                                                                                    
    // No.  Appends to the end of the list.                                                                                   
     test_cases_.push_back(new_test_case);                                                                                     
   }                                                                                                                           
   //最后保存该测试用例的节点号,为了重新洗牌和恢复                                                                                                                            
   test_case_indices_.push_back(static_cast<int>(test_case_indices_.size()));                                                  
   return new_test_case;                                                                                                       
 }                         
8. 最后来看一下GetCase中的AddTestInfo
  • 目的是保存测试特例,因为每一个测试用例都包含多组测试特例
  • 将其索引也保存下来,方便后面调度的时候好找
void TestCase::AddTestInfo(TestInfo * test_info) {                                                                            
   test_info_list_.push_back(test_info);                                                                                       
   test_indices_.push_back(static_cast<int>(test_indices_.size()));                                                            
 }    

三、总结

  至此,TEST宏的源码已经全部展示完毕;我们可以看出TEST宏将运行测试用例之前的工作全部做完,接下来就是运行测试用例的过程;这些准备工作有以下几个步骤:
  

  1. 将test_case_name和test_name拼接起来,实现静态的多态行为

  2. 使用静态成员test_info_进行初始化测试用例的各种信息,对测试用例的所有信息进行注册

  3. 在注册信息时使用MakeAndRegisterTestInfo对test_info_进行初始化和填充信息

  4. 通过TestBody()实现对测试特例代码的执行,在后面执行代码时被调用

  5. 在注册信息中用到了 UnitTest和UnitTestImpl,二者均为单例,实现了注册测试用例信息到GTest中。


注:以上参考https://blog.csdn.net/pillary/article/details/78014546#24-%E6%B3%A8%E5%86%8C%E6%B5%8B%E8%AF%95%E7%94%A8%E4%BE%8B%E4%BF%A1%E6%81%AFmakeandregistertestinfo

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值