google test初步分析

现在常用的C++单元测试框架有 CppUnitCxxTest,boost::testgoogle test。不像java/C#的测试框架,由于C++不支持reflection,所以,必须要做一些额外的工作,让框架知道相关内容的存在。CppUnit的做法是用宏进行注册。这种做法要求我们每添加一个测试,就要考虑用相应的宏进行注册,这种做法很繁琐,最大的问题在于由于疏忽而遗漏,这种靠人工保证的东西不可靠。在这点上,CxxTest 做得要好一些,有一个专门的脚本做这件事。通过这个脚本扫描这个自己编写的文件,生成一些新的文件,完成这个工作。从代码的表现力和可靠度来说,要好得多。唯一的问题是引入了一个脚本,而且这个脚本一般是由某些动态语言写成的(目前的CxxTestPerlPython的脚本),从而引入了对这种语言的依赖。而boost::testgoogle test 则是通过一些宏机制,来实现用户只需写一次就可以自动完成注册。
我大概分析了一下gtest的实现机制。由于里面用了很多宏,比较费解,因此首先用cl /P /C命令将之展开,我的测试程序如下

#include <gtest/gtest.h>
TEST(FactorialTest, Negative) 
{
  EXPECT_EQ(
11);
}


宏展开完后主要部分如下

class FactorialTest_Negative_Test : public ::testing::Test
{
    
public: FactorialTest_Negative_Test()  {}
    
privatevirtual void TestBody();
    
static ::testing::TestInfo* const test_info_;
    FactorialTest_Negative_Test(
const FactorialTest_Negative_Test &);
    
void operator=(const FactorialTest_Negative_Test &);
};

//init test_info_
::testing::TestInfo* const FactorialTest_Negative_Test ::test_info_ = ::testing::internal::MakeAndRegisterTestInfo( "FactorialTest""Negative""""", (::testing::internal::GetTestTypeId()), ::testing::Test::SetUpTestCase, ::testing::Test::TearDownTestCase, new ::testing::internal::TestFactoryImpl< FactorialTest_Negative_Test>);

void FactorialTest_Negative_Test::TestBody()  {
  
// This test is named "Negative", and belongs to the "FactorialTest"
  // test case.
  switch (0case 0if (const ::testing::AssertionResult gtest_ar = (::testing::internal:: EqHelper<(sizeof(::testing::internal::IsNullLiteralHelper(1)) == 1)>::Compare("1""Factorial(-5)"1, Factorial(-5)))) ; else ::testing::internal::AssertHelper(::testing::TPRT_NONFATAL_FAILURE, "sample1_unittest.cc"82, gtest_ar.failure_message()) = ::testing::Message();

}



可以看出,gtest是利用static变量的初始化来实现函数注册的,主要函数为MakeAndRegisterTestInfo(),该函数定义在src/gtest.cc里面

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


果然不出所料,GetUnitTestImpl()->AddTestInfoxx)这一句就是做注册,下面我仿照gtest自己写了一个简单的测试框架

#include <string>
#include <vector>
#include <iostream>
using namespace std;

class Test
{
    
public:
    
virtual bool testBody() = 0;
};

class TestInfo
{
    
public:
        TestInfo(
const char *fun,const char *file,int line, Test * pTest):
        szFunction_(fun),szFile_(file),line_(line),test_(pTest)
        
{
        }
        
        
bool RunTest()
        
{
            
return test_->testBody();
        }
        
        
string szFunction_;
        
string szFile_;
        
int     line_;
    
private:
        
        Test    *test_;
};

typedef    vector < TestInfo *> TestInfosType;
TestInfosType testInfos;

TestInfo * MakeAndRegisterTestInfo(
const char *fun,const char *file,int line, Test * pTest)
{
    
//cout << "MakeAndRegisterTestInfo../n";
    TestInfo * pInfo = new TestInfo(fun, file,line,pTest);
    testInfos.push_back(pInfo);
    
return pInfo;
}

#define TEST(testName)    /
class TEST_##testName: public Test    /
{                    /
    
public:    /
    
virtual bool testBody();    /
    
static TestInfo * test_info_;    /
};    /
TestInfo * TEST_##testName::test_info_ = MakeAndRegisterTestInfo(#testName,__FILE__,__LINE__,
new TEST_##testName);    /
bool TEST_##testName::testBody()    


#define TEST_ASSERT(x)  {if(!(x)) {cout << "AssertFail:" << #x << " File:" << test_info_->szFile_.c_str() << " Line:" << test_info_->line_ << " Function:" << test_info_->szFunction_.c_str() << endl;return false;}else cout<<"."<<endl;}

#define RUN_ALL_TEST()    /
for(TestInfosType::iterator it = testInfos.begin();    /
        it != testInfos.end(); ++it)    /
{    /
    TestInfo * pInfo = *it;    /
    pInfo->RunTest();    /
}    /



使用该测试框架的方法如下

TEST(test1)
{
    TEST_ASSERT(
2==2);
    TEST_ASSERT(
2==1);
}

TEST(test2)
{
    TEST_ASSERT(
3==3);
    TEST_ASSERT(
2==3);
}


void main()
{
    cout << 
"start test../n";
    RUN_ALL_TEST();
}



输出结果:

I:/VC2008/gtest-1.2.1>mySimulate.exe
start test..
.
AssertFail:2==1 File:mySimulate.cpp Line:66 Function:test1
.
AssertFail:2==3 File:mySimulate.cpp Line:72 Function:test2

尚有点问题就是,现实的错误行号其实为函数第一行的行号。

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值