深入解析gtest

单元测试gtest的安装与使用方法【结合官网的sample】 gtest单元测试是Google的一套用于编写C++测试的框架,可以运行在很多平台上(包括Linux、Mac OS X、Windows、Cygwin等等)。基于xUnit架构。支持很多好用的特性,包括自动识别测试、丰富的断言、断言自定义、死亡测试、非终止的失败、生成XML报告等等,本文对gtest的安装以及基本使用方法进行细致说明,希望对您有所帮助。 阅读详情
转:http://www.cnblogs.com/coderzh/archive/2009/04/11/1433744.html

一、前言

“深入解析”对我来说的确有些难度,所以我尽量将我学习到和观察到的gtest内部实现介绍给大家。本文算是抛砖引玉吧,只能是对gtest的整体结构的一些介绍,想要了解更多细节最好的办法还是看gtest源码,如果你看过gtest源码,你会发现里面的注释非常的详细!好了,下面就开始了解gtest吧。

二、从TEST宏开始

前面的文章已经介绍过TEST宏的用法了,通过TEST宏,我们可以非法简单、方便的编写测试案例,比如:

TEST(FooTest, Demo)
{
    EXPECT_EQ(
1 ,  1 );
}

 

我们先不去看TEST宏的定义,而是先使用/P参数将TEST展开。如果使用的是Vistual Studio的话:

1. 选中需要展开的代码文件,右键 - 属性 - C/C++ - Preprocessor

2. Generate Preprocessed File 设置 Without Line Numbers (/EP /P) 或 With Line Numbers (/P)

3. 关闭属性对话框,右键选中需要展开的文件,右键菜单中点击:Compile

编译过后,会在源代码目录生成一个后缀为.i的文件,比如我对上面的代码进行展开,展开后的内容为:

复制代码
class  FooTest_Demo_Test :  public  ::testing::Test 
{
public : 
    FooTest_Demo_Test() {}
private : 
    
virtual   void  TestBody();
    
static  ::testing::TestInfo *   const  test_info_;
    FooTest_Demo_Test(
const  FooTest_Demo_Test  & );
    
void   operator = ( const  FooTest_Demo_Test  & );
};

::testing::TestInfo
*   const  FooTest_Demo_Test 
    ::test_info_ 
=  
        ::testing::
internal ::MakeAndRegisterTestInfo( 
            
" FooTest " ,  " Demo " ,  "" ,  "" ,
            (::testing::
internal ::GetTestTypeId()),
            ::testing::Test::SetUpTestCase,
            ::testing::Test::TearDownTestCase,
            
new  ::testing:: internal ::TestFactoryImpl <  FooTest_Demo_Test > );

void  FooTest_Demo_Test::TestBody()
{
    
switch  ( 0 )
    
case   0 :
        
if  ( const  ::testing::AssertionResult 
                gtest_ar 
=  
                    (::testing::
internal :: EqHelper < ( sizeof (::testing:: internal ::IsNullLiteralHelper( 1 ))  ==   1 ) > ::Compare( " 1 " ,  " 1 " ,  1 ,  1 )))
            ;
        
else  
            ::testing::
internal ::AssertHelper(
                ::testing::TPRT_NONFATAL_FAILURE,
                
" .\\gtest_demo.cpp " ,
                
9 ,
                gtest_ar.failure_message()
                ) 
=  ::testing::Message();
}
复制代码

 

展开后,我们观察到:

1. TEST宏展开后,是一个继承自testing::Test的类。

2. 我们在TEST宏里面写的测试代码,其实是被放到了类的TestBody方法中。

3. 通过静态变量test_info_,调用MakeAndRegisterTestInfo对测试案例进行注册。

如下图:



上面关键的方法就是MakeAndRegisterTestInfo了,我们跳到MakeAndRegisterTestInfo函数中:

复制代码
//  创建一个 TestInfo 对象并注册到 Google Test;
//  返回创建的TestInfo对象
//
//  参数:
//
//    test_case_name:            测试案例的名称
//    name:                           测试的名称
//    test_case_comment:       测试案例的注释信息
//    comment:                      测试的注释信息
//    fixture_class_id:             test fixture类的ID
//    set_up_tc:                    事件函数SetUpTestCases的函数地址
//    tear_down_tc:               事件函数TearDownTestCases的函数地址
//    factory:                        工厂对象,用于创建测试对象(Test)
TestInfo *  MakeAndRegisterTestInfo(
    
const   char *  test_case_name,  const   char *  name,
    
const   char *  test_case_comment,  const   char *  comment,
    TypeId fixture_class_id,
    SetUpTestCaseFunc set_up_tc,
    TearDownTestCaseFunc tear_down_tc,
    TestFactoryBase
*  factory) {
  TestInfo
*   const  test_info  =
      
new  TestInfo(test_case_name, name, test_case_comment, comment,
                   fixture_class_id, factory);
  GetUnitTestImpl()
-> AddTestInfo(set_up_tc, tear_down_tc, test_info);
  
return  test_info;
}
复制代码

 

我们看到,上面创建了一个TestInfo对象,然后通过AddTestInfo注册了这个对象。TestInfo对象到底是一个什么样的东西呢?

TestInfo对象主要用于包含如下信息:

1. 测试案例名称(testcase name)

2. 测试名称(test name)

3. 该案例是否需要执行

4. 执行案例时,用于创建Test对象的函数指针

5. 测试结果 

我们还看到,TestInfo的构造函数中,非常重要的一个参数就是工厂对象,它主要负责在运行测试案例时创建出Test对象。我们看到我们上面的例子的factory为:

new  ::testing:: internal ::TestFactoryImpl <  FooTest_Demo_Test >

 

我们明白了,Test对象原来就是TEST宏展开后的那个类的对象(FooTest_Demo_Test),再看看TestFactoryImpl的实现:

template  < class  TestClass >
class  TestFactoryImpl :  public  TestFactoryBase {
public :
    
virtual  Test *  CreateTest() {  return   new  TestClass; }
};

 

这个对象工厂够简单吧,嗯,Simple is better。当我们需要创建一个测试对象(Test)时,调用factory的CreateTest()方法就可以了。 

创建了TestInfo对象后,再通过下面的方法对TestInfo对象进行注册:

GetUnitTestImpl() -> AddTestInfo(set_up_tc, tear_down_tc, test_info);

 

GetUnitTestImpl()是获取UnitTestImpl对象:

inline UnitTestImpl *  GetUnitTestImpl() {
    
return  UnitTest::GetInstance() -> impl();
}

 

其中UnitTest是一个单件(Singleton),整个进程空间只有一个实例,通过UnitTest::GetInstance()获取单件的实例。上面的代码看到,UnitTestImpl对象是最终是从UnitTest对象中获取的。那么UnitTestImpl到底是一个什么样的东西呢?可以这样理解:

UnitTestImpl是一个在UnitTest内部使用的,为执行单元测试案例而提供了一系列实现的那么一个类。(自己归纳的,可能不准确)

我们上面的AddTestInfo就是其中的一个实现,负责注册TestInfo实例:

 

复制代码
//  添加TestInfo对象到整个单元测试中
//
//  参数:
//
//    set_up_tc:       事件函数SetUpTestCases的函数地址
//    tear_down_tc:  事件函数TearDownTestCases的函数地址
//    test_info:        TestInfo对象
void  AddTestInfo(Test::SetUpTestCaseFunc set_up_tc,
               Test::TearDownTestCaseFunc tear_down_tc,
               TestInfo 
*  test_info) {
//  处理死亡测试的代码,先不关注它
if  (original_working_dir_.IsEmpty()) {
    original_working_dir_.Set(FilePath::GetCurrentDir());
    
if  (original_working_dir_.IsEmpty()) {
        printf(
" %s\n " ,  " Failed to get the current working directory. " );
        abort();
    }
}
//  获取或创建了一个TestCase对象,并将testinfo添加到TestCase对象中。
GetTestCase(test_info -> test_case_name(),
            test_info
-> test_case_comment(),
            set_up_tc,
            tear_down_tc)
-> AddTestInfo(test_info);
}
复制代码

我们看到,TestCase对象出来了,并通过AddTestInfo添加了一个TestInfo对象。这时,似乎豁然开朗了:

1. TEST宏中的两个参数,第一个参数testcase_name,就是TestCase对象的名称,第二个参数test_name就是Test对象的名称。而TestInfo包含了一个测试案例的一系列信息。

2. 一个TestCase对象对应一个或多个TestInfo对象。


 

我们来看看TestCase的创建过程(UnitTestImpl::GetTestCase):

复制代码
//  查找并返回一个指定名称的TestCase对象。如果对象不存在,则创建一个并返回
//
//  参数:
//
//    test_case_name:    测试案例名称
//    set_up_tc:             事件函数SetUpTestCases的函数地址
//    tear_down_tc:        事件函数TearDownTestCases的函数地址
TestCase *  UnitTestImpl::GetTestCase( const   char *  test_case_name,
                                    
const   char *  comment,
                                    Test::SetUpTestCaseFunc set_up_tc,
                                    Test::TearDownTestCaseFunc tear_down_tc) {
  
//  从test_cases里查找指定名称的TestCase
     internal ::ListNode < TestCase *>*  node  =  test_cases_.FindIf(
        TestCaseNameIs(test_case_name));

    
if  (node  ==  NULL) {
        
//  没找到,我们来创建一个
        TestCase *   const  test_case  =
            
new  TestCase(test_case_name, comment, set_up_tc, tear_down_tc);

        
//  判断是否为死亡测试案例
         if  ( internal ::UnitTestOptions::MatchesFilter(String(test_case_name),
                                                 kDeathTestCaseFilter)) {
            
//  是的话,将该案例插入到最后一个死亡测试案例后
            node  =  test_cases_.InsertAfter(last_death_test_case_, test_case);
            last_death_test_case_ 
=  node;
        } 
else  {
            
//  否则,添加到test_cases最后。
            test_cases_.PushBack(test_case);
            node 
=  test_cases_.Last();
        }
    }

    
//  返回TestCase对象
     return  node -> element();
}
复制代码

 

三、回过头看看TEST宏的定义
#define  TEST(test_case_name, test_name)\
    GTEST_TEST_(test_case_name, test_name, \
              ::testing::Test, ::testing::
internal ::GetTestTypeId())

 

同时也看看TEST_F宏

#define  TEST_F(test_fixture, test_name)\
    GTEST_TEST_(test_fixture, test_name, test_fixture, \
              ::testing::
internal ::GetTypeId < test_fixture > ())

都是使用了GTEST_TEST_宏,在看看这个宏如何定义的:

复制代码
#define  GTEST_TEST_(test_case_name, test_name, parent_class, parent_id)\
class  GTEST_TEST_CLASS_NAME_(test_case_name, test_name) :  public  parent_class {\
public :\
    GTEST_TEST_CLASS_NAME_(test_case_name, test_name)() {}\
private :\
    
virtual   void  TestBody();\
    
static  ::testing::TestInfo *   const  test_info_;\
    GTEST_DISALLOW_COPY_AND_ASSIGN_(\
        GTEST_TEST_CLASS_NAME_(test_case_name, test_name));\
};\
\
::testing::TestInfo
*   const  GTEST_TEST_CLASS_NAME_(test_case_name, test_name)\
    ::test_info_ 
= \
        ::testing::
internal ::MakeAndRegisterTestInfo(\
            #test_case_name, #test_name, 
"" ,  "" , \
            (parent_id), \
            parent_class::SetUpTestCase, \
            parent_class::TearDownTestCase, \
            
new  ::testing:: internal ::TestFactoryImpl < \
                GTEST_TEST_CLASS_NAME_(test_case_name, test_name)
> );\
void  GTEST_TEST_CLASS_NAME_(test_case_name, test_name)::TestBody()
复制代码

 

不需要多解释了,和我们上面展开看到的差不多,不过这里比较明确的看到了,我们在TEST宏里写的就是TestBody里的东西。这里再补充说明一下里面的GTEST_DISALLOW_COPY_AND_ASSIGN_宏,我们上面的例子看出,这个宏展开后:

FooTest_Demo_Test( const  FooTest_Demo_Test  & );
void   operator = ( const  FooTest_Demo_Test  & );

 

正如这个宏的名字一样,它是用于防止对对象进行拷贝和赋值操作的。 

四、再来了解RUN_ALL_TESTS宏

我们的测试案例的运行就是通过这个宏发起的。RUN_ALL_TEST的定义非常简单:

#define  RUN_ALL_TESTS()\
    (::testing::UnitTest::GetInstance()
-> Run())

 

我们又看到了熟悉的::testing::UnitTest::GetInstance(),看来案例的执行时从UnitTest的Run方法开始的,我提取了一些Run中的关键代码,如下:

复制代码
int  UnitTest::Run() {
    __try {
        
return  impl_ -> RunAllTests();
    } __except(
internal ::UnitTestOptions::GTestShouldProcessSEH(
        GetExceptionCode())) {
        printf(
" Exception thrown with code 0x%x.\nFAIL\n " , GetExceptionCode());
        fflush(stdout);
        
return   1 ;
    }

    
return  impl_ -> RunAllTests();
}
复制代码

 

我们又看到了熟悉的impl(UnitTestImpl),具体案例该怎么执行,还是得靠UnitTestImpl。

复制代码
int  UnitTestImpl::RunAllTests() {

    
//  ...

    printer
-> OnUnitTestStart(parent_);

    
//  计时
     const  TimeInMillis start  =  GetTimeInMillis();

    printer
-> OnGlobalSetUpStart(parent_);
    
//  执行全局的SetUp事件
    environments_.ForEach(SetUpEnvironment);
    printer
-> OnGlobalSetUpEnd(parent_);

    
//  全局的SetUp事件执行成功的话
     if  ( ! Test::HasFatalFailure()) {
        
//  执行每个测试案例
        test_cases_.ForEach(TestCase::RunTestCase);
    }

    
//  执行全局的TearDown事件
    printer -> OnGlobalTearDownStart(parent_);
    environments_in_reverse_order_.ForEach(TearDownEnvironment);
    printer
-> OnGlobalTearDownEnd(parent_);

    elapsed_time_ 
=  GetTimeInMillis()  -  start;

    
//  执行完成
    printer -> OnUnitTestEnd(parent_);

    
//  Gets the result and clears it.
     if  ( ! Passed()) {
      failed 
=   true ;
    }
    ClearResult();

    
//  返回测试结果
     return  failed  ?   1  :  0 ;
}
复制代码

 

上面,我们很开心的看到了我们前面讲到的全局事件的调用。environments_是一个Environment的链表结构(List),它的内容是我们在main中通过:

testing::AddGlobalTestEnvironment( new  FooEnvironment);

 

添加进去的。test_cases_我们之前也了解过了,是一个TestCase的链表结构(List)。gtest实现了一个链表,并且提供了一个Foreach方法,迭代调用某个函数,并将里面的元素作为函数的参数:

复制代码
template  < typename F >    //  F is the type of the function/functor
void  ForEach(F functor)  const  {
    
for  (  const  ListNode < E >   *  node  =  Head();
          node 
!=  NULL;
          node 
=  node -> next() ) {
      functor(node
-> element());
    }
}
复制代码

 

因此,我们关注一下:environments_.ForEach(SetUpEnvironment),其实是迭代调用了SetUpEnvironment函数:

static   void  SetUpEnvironment(Environment *  env) { env -> SetUp(); }

 

最终调用了我们定义的SetUp()函数。

再看看test_cases_.ForEach(TestCase::RunTestCase)的TestCase::RunTestCase实现:

static   void  RunTestCase(TestCase  *  test_case) { test_case -> Run(); }

 

再看TestCase的Run实现:

复制代码
void  TestCase::Run() {
    
if  ( ! should_run_)  return ;

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

    UnitTestEventListenerInterface 
*   const  result_printer  =
    impl
-> result_printer();

    result_printer
-> OnTestCaseStart( this );
    impl
-> os_stack_trace_getter() -> UponLeavingGTest();
    
//  哈!SetUpTestCases事件在这里调用
    set_up_tc_();

    
const   internal ::TimeInMillis start  =   internal ::GetTimeInMillis();
    
//  嗯,前面分析的一个TestCase对应多个TestInfo,因此,在这里迭代对TestInfo调用RunTest方法
    test_info_list_ -> ForEach( internal ::TestInfoImpl::RunTest);
    elapsed_time_ 
=   internal ::GetTimeInMillis()  -  start;

    impl
-> os_stack_trace_getter() -> UponLeavingGTest();
    
//  TearDownTestCases事件在这里调用
    tear_down_tc_();
    result_printer
-> OnTestCaseEnd( this );
    impl
-> set_current_test_case(NULL);
}
复制代码

第二种事件机制又浮出我们眼前,非常兴奋。可以看出,SetUpTestCases和TearDownTestCaess是在一个TestCase之前和之后调用的。接着看test_info_list_->ForEach(internal::TestInfoImpl::RunTest):

static   void  RunTest(TestInfo  *  test_info) {
    test_info
-> impl() -> Run();
}

哦?TestInfo也有一个impl?看来我们之前漏掉了点东西,和UnitTest很类似,TestInfo内部也有一个主管各种实现的类,那就是TestInfoImpl,它在TestInfo的构造函数中创建了出来(还记得前面讲的TestInfo的创建过程吗?):

复制代码
TestInfo::TestInfo( const   char *  test_case_name,
                   
const   char *  name,
                   
const   char *  test_case_comment,
                   
const   char *  comment,
                   
internal ::TypeId fixture_class_id,
                   
internal ::TestFactoryBase *  factory) {
    impl_ 
=   new   internal ::TestInfoImpl( this , test_case_name, name,
                                     test_case_comment, comment,
                                     fixture_class_id, factory);
}
复制代码

 

因此,案例的执行还得看TestInfoImpl的Run()方法,同样,我简化一下,只列出关键部分的代码:

复制代码
void  TestInfoImpl::Run() {

    // ...

    UnitTestEventListenerInterface *   const  result_printer  =
        impl
-> result_printer();
    result_printer
-> OnTestStart(parent_);
    
//  开始计时
    
const  TimeInMillis start  =  GetTimeInMillis();

    Test *  test  =  NULL;

    __try {
        
//  我们的对象工厂,使用CreateTest()生成Test对象
        test  =  factory_ -> CreateTest();
    } __except(
internal ::UnitTestOptions::GTestShouldProcessSEH(
        GetExceptionCode())) {
        AddExceptionThrownFailure(GetExceptionCode(),
                              
" the test fixture's constructor " );
        
return ;

    }

     //  如果Test对象创建成功

    if (!Test::HasFatalFailure()) {

        // 调用Test对象的Run()方法,执行测试案例 

        test -> Run();
    }

    
//  执行完毕,删除Test对象
    impl -> os_stack_trace_getter() -> UponLeavingGTest();
    delete test;
    test 
=  NULL;

     //  停止计时
    result_.set_elapsed_time(GetTimeInMillis()  -  start);
    result_printer -> OnTestEnd(parent_);

}
复制代码

 

上面看到了我们前面讲到的对象工厂fatory,通过fatory的CreateTest()方法,创建Test对象,然后执行案例又是通过Test对象的Run()方法:

复制代码
void  Test::Run() {
    
if  ( ! HasSameFixtureClass())  return ;

    
internal ::UnitTestImpl *   const  impl  =   internal ::GetUnitTestImpl();
    impl
-> os_stack_trace_getter() -> UponLeavingGTest();
    __try {
        
//  Yeah!每个案例的SetUp事件在这里调用
        SetUp();
    } __except(
internal ::UnitTestOptions::GTestShouldProcessSEH(
        GetExceptionCode())) {
        AddExceptionThrownFailure(GetExceptionCode(), 
" SetUp() " );
    }

    
//  We will run the test only if SetUp() had no fatal failure.
     if  ( ! HasFatalFailure()) {
        impl
-> os_stack_trace_getter() -> UponLeavingGTest();
        __try {
            
//  哈哈!!千辛万苦,我们定义在TEST宏里的东西终于被调用了!
            TestBody();
        } __except(
internal ::UnitTestOptions::GTestShouldProcessSEH(
            GetExceptionCode())) {
            AddExceptionThrownFailure(GetExceptionCode(), 
" the test body " );
        }
    }

    impl
-> os_stack_trace_getter() -> UponLeavingGTest();
    __try {
        
//  每个案例的TearDown事件在这里调用
        TearDown();
    } __except(
internal ::UnitTestOptions::GTestShouldProcessSEH(
        GetExceptionCode())) {
        AddExceptionThrownFailure(GetExceptionCode(), 
" TearDown() " );
    }
}
复制代码

 

上面的代码里非常极其以及特别的兴奋的看到了执行测试案例的前后事件,测试案例执行TestBody()的代码。仿佛整个gtest的流程在眼前一目了然了。

四、总结

本文通过分析TEST宏和RUN_ALL_TEST宏,了解到了整个gtest运作过程,可以说整个过程简洁而优美。之前读《代码之美》,感触颇深,现在读过gtest代码,再次让我感触深刻。记得很早前,我对设计的理解是“功能越强大越好,设计越复杂越好,那样才显得牛”,渐渐得,我才发现,简单才是最好。我曾总结过自己写代码的设计原则:功能明确,设计简单。了解了gtest代码后,猛然发现gtest不就是这样吗,同时gtest也给了我很多惊喜,因此,我对gtest的评价是:功能强大,设计简单,使用方便。

总结一下gtest里的几个关键的对象:

1. UnitTest 单例,总管整个测试,包括测试环境信息,当前执行状态等等。

2. UnitTestImpl UnitTest内部具体功能的实现者。

3. Test    我们自己编写的,或通过TEST,TEST_F等宏展开后的Test对象,管理着测试案例的前后事件,具体的执行代码TestBody。

4. TestCase 测试案例对象,管理着基于TestCase的前后事件,管理内部多个TestInfo。

5. TestInfo  管理着测试案例的基本信息,包括Test对象的创建方法。 

6. TestInfoImpl TestInfo内部具体功能的实现者 。

本文还有很多gtest的细节没有分析到,比如运行参数,死亡测试,跨平台处理,断言的宏等等,希望读者自己把源码下载下来慢慢研究。如本文有错误之处,也请大家指出,谢谢!

gtest测试框架 本文主要介绍gtest原理以及使用 阅读详情

相关推荐

一文读懂测试单元gtest

gtest 是 Google 开发的 C++ 单元测试框架,提供了丰富的断言、测试夹具和测试运行器等功能,帮助开发者编写高效、可维护的测试代码。好的测试单元应具备独立性、结构化组织、跨平台兼容性、丰富的失败信息、低维护成本和高执行效率等特点。gtest 通过自动注册机制、参数化测试和并行执行等特性,减少了测试代码的重复性,提升了测试效率。安装 gtest 可以通过克隆 GitHub 仓库并使用 CMake 进行编译和安装。gtest 的断言分为非致命断言(EXPECT_)和致命断言(ASSERT_),支持布

m0_73359068的博客 2366

gtest学习

gtest个人学习整理分享。

weixin_51032194的博客 1万+

深入解析gtest源码及测试实践

本文还有配套的精品资源,点击获取 简介:gtest,即Google Test,是Google提供的开源C++测试框架,便于开发者编写和运行单元测试,确保代码质量。本文将深入探讨gtest的源码,了解其内部机制和提高C++测试实践的方法。gtest源码涵盖测试用例和测试点的管理、断言库的实现、自定义类型断言支持、测试参数化方法、命令行选项处理和XML测试结果输出等方面。通过研...

weixin_32312889的博客 1255

【gTest】gtest简介及简单使用

【gTest】gtest简介及简单使用 gtest是一个跨平台(Liunx、Mac OS X、Windows、Cygwin、Windows CE and Symbian)的C++测试框架,有google公司发布。gtest测试框架是在不同平台上为编写C++测试而生成的。 从http://code.google.com/p/googletest/downloads/detail?name=gtest-1.7.0.zip&can=2&q=下载最新的gtest-1.7.0版本 在Windows下编

qq_43331089的博客 2万+

FFmpeg魔改指南:让RTMP协议完美兼容H265的三种方法(含SRS适配技巧)

本文详细介绍了三种让RTMP协议兼容H265编码的FFmpeg魔改方案,包括基于官方补丁的标准改造、Intel的SVT-HEVC集成方案以及金山云的自定义扩展方案。文章重点解析了各方案的实现原理与适配技巧,并提供了在SRS 6.0服务器上进行深度配置和性能调优的完整实战指南,帮助开发者解决H265推流至传统RTMP服务器的兼容性问题。

weixin_29290947的博客 195

从深算一号到三号:海光DCU的技术演进与国产超算突围之路

本文梳理了海光DCU从深算一号到三号的技术演进历程,展现了国产高性能计算芯片从填补空白到追赶并行的突围之路。文章重点分析了深算系列在性能提升、软件生态(DTK)建设及超算平台构建方面的关键进展,并探讨了其在AI大模型训练、科学计算等领域的应用实践与未来挑战。

ipfs8storage的博客 1062

C++单元测试框架-gtest-4-深入解析gtest

把测试宏展开,深入分析代码的行为

shenwanjiang111的专栏 1489

微带天线理论学习笔记(1)

微带天线的概念是由Deschamps于1953年提出来的,它是在一块厚度远小于工作波长的介质基片的一面敷以金属辐射片、一面全部敷以金属薄层作接地板而成。辐射片可以根据不同的要求设计成各种形状。微带天线具有质量轻、体积小和易于制造等优点,广泛应用于个人无线通信中。

qq_36521926的博客 6227

Gtest:源码解析

转自:玩转Google开源C++单元测试框架Google Test系列(gtest)之七 - 深入解析gtest 一、前言 “深入解析”对我来说的确有些难度,所以我尽量将我学习到和观察到的gtest内部实现介绍给大家。本文算是抛砖引玉吧,只能是对gtest的整体结构的一些介绍,想要了解更多细节最好的办法还是看gtest源码,如果你看过gtest源码,你会发现里面的注释非常的详细!好了,下面就开...

weixin_34075551的博客 647

《最游记》游戏开发全栈指南:从源码解析到实战部署

本文提供了一份详尽的《最游记》游戏源码全栈开发指南。文章深入解析了这款3D玄幻网游的完整源码结构,涵盖客户端、服务端、引擎和工具链,并提供了从环境搭建、核心模块解析到实战修改与部署的完整流程。对于希望深入理解MMORPG架构的开发者而言,这份指南是宝贵的实战资源。

weixin_28363123的博客 72

深入解析WIFI与蓝牙模块电路设计:从原理到实战

本文深入解析了WIFI与蓝牙模块的电路设计,从核心原理到实战应用。文章以AP6256模块为例,详细拆解了电源树、时钟电路、接口设计及天线射频路径等关键环节,并提供了PCB布局布线的实用准则与调试方法,旨在帮助硬件工程师设计出稳定可靠的无线产品,规避常见陷阱。

weixin_29186249的博客 150

玩转Google开源C++单元测试框架Google Test系列(gtest)之七 - 深入解析gtest

了解了gtest代码后,猛然发现gtest不就是这样吗,同时gtest也给了我很多惊喜,因此,我对gtest的评价是:功能强大,设计简单,使用方便。本文算是抛砖引玉吧,只能是对gtest的整体结构的一些介绍,想要了解更多细节最好的办法还是看gtest源码,如果你看过gtest源码,你会发现里面的注释非常的详细!3. Test 我们自己编写的,或通过TEST,TEST_F等宏展开后的Test对象,管理着测试案例的前后事件,具体的执行代码TestBody。

梦心之魂的博客 3128

YOLOv13涨点改进| CVPR 2026 |独家创新首发、主干改进篇 |利用RIS-PiDiNet主干让YOLOv13更加强大!适合遥感目标检测、小目标检测、旋转目标检测,变化检测,图像分割涨点

🔥本文提出了一种改进的RIS-PiDiNet主干网络,通过引入几何先验构建几何一致性检测器,显著提升了模型在任意方向、结构规则目标场景下的检测性能。包含两个核心模块:S-PDC利用极谐变换的谐波核建模目标结构对称性,RIS-PDC通过SO(2)群平均实现旋转不变性。网络采用基于RIS-block的主干结构并融合轻量级LBP特征,增强了细粒度结构表达能力。实验表明,该方法特别适用于遥感和复杂几何分布场景,能有效提升目标检测的鲁棒性和精度。文章还详细介绍了如何将RIS-PiDiNet集成到YOLOv13框架

Ai缝合怪、助力小伙伴高效发论文 90

深入解析Gtest

公司最近需要在用Gtest框架,进行修改,实现自己的测试框架,这段时间一直在看gtest源码,这篇文章从网上找到,对自己非常有帮助,贴出来供大家学习,转载地址:http://www.cnblogs.com/coderzh/archive/2009/04/11/1433744.html 过几天自己也需要总结一下对gtest的理解,以备后用 一、前言 “深入解析”对我来说

做一个有技术追求的人 5561

★教程1:matlab学习教程入门100例目录

★基础入门 1.为什么要学习MATLAB 2.MATLAB安装 持续更新....... ★MATLAB基础编程语言熟悉

FPGA/MATLAB学习教程/源码/项目合作开发 4万+

使用Python爬虫获取Facebook帖子和评论数据

Web爬虫是用于自动抓取网页数据的程序。它通过发送HTTP请求,获取网页的HTML源代码,再对源代码进行解析,提取所需的内容。爬虫常用于数据收集、信息提取、数据分析等应用。

2201_76125261的博客 1998

Google Test(GTest)使用方法和源码解析——概况

GTest是很多开源工程的测试框架。虽然介绍它的博文非常多,但是我觉得可以深入到源码层来解析它的实现原理以及使用方法。这样我们不仅可以在开源工程中学习到实用知识,还能学习到一些思想和技巧。我觉得有时候思想和技巧是更重要的。(转载请指明出于breaksoftware的csdn博客) 我们即将要分析的是GTest1.7版本。我们可以通过https://github.com/google/googletest.git得到代码。 官方文档见: https://github.co...

Sudouble的专栏 883

jre9下载 jdk9

(Java SE Runtime Environment 9.0) 9.0u175 官方最新版 【x86|x64】

最全面的gtest的TEST宏源码解析及自动调度机制

GTEST的TEST原理分析及自动调度解析 介绍 Gtest是google开发的一个开源的C++测试框架,可在Linux, Windows,Mac多个平台上对C++源码进行测试,它提供了丰富的断言、致命和非致命判断、参数化、”死亡测试”等等。 使用gtest时,就是编写断言(assertions),断言语句会检测条件是否为真。一个断言可存在三种结果:success(成功),nonfatal failure(非致命失败),或 fatal failure(致命失败)。当出现致命失败时,终止当前函数;否则程序继续

Jayse的博客 3070

文档:亲测可用解决vnc灰屏,黑屏,鼠标大黑叉情况

主要解决vnc-viewer灰屏,黑屏,鼠标大黑叉等现象,详细见文档。

visio安装包

Microsoft Office Visio 是一款专业的制图软件。利用经过更新的形状、协作工具和数据链接图表,创建专业级图表以简化复杂的信息。

Gtest源码解析 - GoogleTest(八)

一、前言 “深入解析”对我来说的确有些难度,所以我尽量将我学习到和观察到的gtest内部实现介绍给大家。本文算是抛砖引玉吧,只能是对gtest的整体结构的一些介绍,想要了解更多细节最好的办法还是看gtest源码,如果你看过gtest源码,你会发现里面的注释非常的详细!好了,下面就开始了解gtest吧。 二、从TEST宏开始 前面的文章已经介绍过TEST宏的用法了,通过TEST宏,我们可以非法简单、方便的编写测试案例,比如: TEST(FooTest,Demo) { EXPECT_EQ(1,...

生活需要深度 2239

Camera2Demo

在Camera2 的基础上进行封装,使得Camera2一堆初始化逻辑与Activity分离,降低耦合度,完成预览拍照并保存的操作

玩转Google开源C++单元测试框架Google Test系列(gtest)之七 - 深入解析gtest [转载]

一、前言“深入解析”对我来说的确有些难度,所以我尽量将我学习到和观察到的gtest内部实现介绍给大家。本文算是抛砖引玉吧,只能是对gtest的整体结构的一些介绍,想要了解更多细节最好的办法还是看gtest源码,如果你看过gtest源码,你会发现里面的注释非常的详细!好了,下面就开始了解gtest吧。二、从TEST宏开始前面的文章已经介绍过TEST宏的用法了,通过TEST宏,我们可以非法简单、方便的...

我的博客 327

(转)玩转Google开源C++单元测试框架Google Test系列(gtest)之七 - 深入解析gtest

原文链接:http://www.cnblogs.com/coderzh/archive/2009/04/11/1433744.html 一、前言 “深入解析”对我来说的确有些难度,所以我尽量将我学习到和观察到的gtest内部实现介绍给大家。本文算是抛砖引玉吧,只能是对gtest的整体结构的一些介绍,想要了解更多细节最好的办法还是看gtest源码,如果你看过gtest源码...

dengshen7813的博客 164
上一篇: 深入理解Javascript闭包
下一篇: Function 与 Functor 区别
Superr爬爬虫
博客等级 码龄19年 72粉丝 93原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值