gtest
今天学习使用了gtest。gtest 主要使用方法就是在一个 TEST() / TEST_F () 里写测试用例,然后通过在main函数使用 RUN_ALL_TEST() 即可运行 gtest。
对于TEST_F 实际跟TEST 基本一样,但是它多了一个初始化功能,比如我们需要在进行这个测试用例前,需要构造一些临时的测试数据,那么就可以使用TEST_F。TEST_F 在gtest中也称为gtest的事件机制,所谓事件机制就是帮我们在测试列子的时候帮我们干些打杂的事情,比如帮我们生成一些测试数据,然后测试完了做一些清理工作
gtest 事件机制
gtest分为以下三个事件机制
- 全局事件
- test_case
- test
testcase 与 test
我们使用gtest的时候宏函数里面填的内容就是testcase,test。testcase 我的理解就相当于 我们要测那个案例,比如我们写了一个List想用gtest进行测试。testcase就是List,test就是List的具体功能比如插入、删除等等
TEST(testcase,test)
全局事件
这个就是相当于一个全局初始化
// 全局事件
class GlobalTest : public testing::Environment {
public:
virtual void SetUp() {
std::cout << "SetUp" << std::endl;
}
virtual void TearDown() {
std::cout << "TearDown" << std::endl;
}
};
int main(int argc, char* argv[]) {
testing::InitGoogleTest(&argc, argv);
testing::Environment* env = new GlobalTest();
testing::AddGlobalTestEnvironment(env);
return RUN_ALL_TESTS();
}
test_case事件
test_case 的事件使用,TEST_F宏来实现具体测试。然后静态的实现 SetUpTestCase() 和 TearDownTestCase() 函数即可。使用TEST_F宏的时候其test_case必须是一个类名,并且这个类的基本结构如下所示。
它的初始函数(SetUpTestCase)在第一个test运行前执行, 清理函数(TearDownTestCase)在最后一个test运行后执行。
class test_case :: public testing::Test
{
static void SetUpTestCase() {
shared_resource_ = new ;
}
static void TearDownTestCase() {
delete shared_resource_;
shared_resource_ = NULL;
}
TEST_F(test_case,test)
{
}
test事件
主要的主人公test事件级的测试,因为大多数我们都想每测一个功能,测试数据都不会收影响,所以每次测试的时候测试数据重新再次生成一遍是最好的了。它使用跟上面那个差不多,主要实现SetUp和TearDown即可。
主要使用起来,让我们感到舒服的是,我们可以把关于这个test_case的所有功能都以成员函数的方式写到自己实现的Test类里,然后在TEST_F宏里面直接调用这些成员函数即可,这样就可以一边测试一边开发,帮助减少bug,这也就是传说中的测试驱动开发(Test Driver Development)
class Data {
void init()
{
构造测试数据
}
void Destroy()
{
释放测试数据
}
};
class Test:: public testing::Test
{
public :
virtual void SetUp()
{
data.init();
}
virtual void TearDown()
{
data.Destroy();
}
void Fun()
{
使用data初始的测试数据然后执行一些关于被测对象的逻辑
}
int TestFun()
{
Fun();
if(A.success)
return 1;
else
return 0;
}
private:
Data data;
A a; //被测数据
}
TEST_F(Test,test1)
{
ASSERT_EQ(1,TestFun());
}
test_F
#include<gtest/gtest.h>
class Foo::public testing::test {
protected :
void Fun()
{}
};
TEST_F(Foo,Foo_test1)
{
Foo::Fun();
}
class Foo::public testing::test {
protected :
void Fun()
{}
};
class Foo_Foo_test1_Test : public Foo {
public:
Foo_Foo_test1_Test() {}
private:
virtual void TestBody();
static ::testing::TestInfo* const test_info_ __attribute__ ((unused));
Foo_Foo_test1_Test(Foo_Foo_test1_Test const &);
void operator=(Foo_Foo_test1_Test const &);
};
::testing::TestInfo* const Foo_Foo_test1_Test ::test_info_ =
::testing::internal::MakeAndRegisterTestInfo( "Foo", "Foo_test1", __null, __null,
(::testing::internal::GetTypeId<Foo>()), Foo::SetUpTestCase, Foo::TearDownTestCase, new
::testing::internal::TestFactoryImpl< Foo_Foo_test1_Test>);
void Foo_Foo_test1_Test::TestBody()
{
Foo::Fun();
}
今天发现为什么TEST_F宏里面可以访问 我们自定义的test类的protected成员。凭直觉我想到能这样处理要么gtest把TEST_F宏的宏函数变成一个实际的函数,然后这个函数是我们自定义test类的友元函数,要么gtest 自定义了一个类,宏函数是这个类的成员函数,然后gtest自定义类继承了我们定义的test类。经过编译宏展开发现,确实gtest自己搞了一个类public继承了我们定义的test类,所以它可以访问test类的protect成员在宏函数中,但是它并没有自己定义一个类似TEST_F宏函数的成员函数,只是把所有TEST_F宏内的内容搬移到了一个TestBody里的函数中,然后转掉这个TestBody而已。
Base64
项目中使用到了很多base64编码,期初我以为这个玩意是用来序列化和反序列化的,但是我发现项目中的数据已经使用了 protobuf序列化后再进行的base64编码,所以我想到可能base64不是用来序列化的,所以一查才发现它是用来处理二进制数据的不可见数据的,因为可能二进制数据在网络传输中因为某些不可见数据或者 CRCF这种导致数据传输错误,所以使用 base64 把二进制数据转换为 纯文本数据方便传输防止出错