基于gtest进行单元测试

技术岗

测试(QA):保证代码没有bug

开发(RD):搬砖

运维(OP):

非技术岗

产品经理

注意公司和部门和岗位和工资

测试时需要先搞清楚需求和功能点

姓名_学校专业_岗位.pdf

1、 软件开发生命周期

 

 

2、 单元测试:

 

# include<cstdio>

//实现一个求绝对值的函数

int Abs(int x){

    return x>0?x:-x;

}

//针对Abs函数进行测试:单元测试必须为一个独立的函数

void TestAbs()

{

    int result=Abs(10);

    if(result==10){

        printf("ok\n");

    }

    else

    {

        printf("NO\n");

    }

    int result=Abs(-10);

if(result==10){

    if(result==10){

        printf("ok  1\n");

    }

    else

    {

        printf("NO   2\n");

    }

    int result=Abs(0);

    if(result==0){

        printf("ok   2\n");

    }

    else

    {

        printf("NO   2\n");

    }

}

int main(){

    TestAbs();

    return 0;

}

 

3、 gtest:谷歌业界广泛使用的单元测试框架:gtest只能用于C++

gtest框架提供了gtest方式的单元测试

gtest中有一个默认的main函数,成功会编程原亮色

 

4、 步骤:

安装gtest

 

main.cc

# include<gtest/gtest.h>

# include<iostream>

 

//TestCase相当于目录,Test相当于目录中的文件

//把一组有关联的Test组织到一个TestCase

//TestCaseName和TestName都要结合实际的测试场景决定

//写一个test宏,进行单元测试的基本单位

Test(HelloTestCase,HelloTest)

{

//TEST宏里面可以写任何合法的C++代码

std::cout<<"hello"<<std::endl;

}

 

Makefile:

 

hello:hello.cc

        g++ $^ -o $@ -I ~/third_part/include

            -L ~/third_part/lib -lgtest -lgtest_main -lpthread

.PHONY:clean

clean:

        rm hello

 

 

5、学会使用第三方库

如何将第三方库引入项目中:

gtest中自定义main函数(添加初始化即可):

 

# include<gtest/gtest.h>

# include<iostream>

 

//TestCase相当于目录,Test相当于目录中的文件

//把一组有关联的Test组织到一个TestCase

//TestCaseName和TestName都要结合实际的测试场景决定

//写一个test宏,进行单元测试的基本单位

Test(HelloTestCase,HelloTest)

{

//TEST宏里面可以写任何合法的C++代码

std::cout<<"hello"<<std::endl;

}

 

 

int main(int argc,char* argv[])

{

 

return RUN_ALL_TESTS();//把返回值作为进程的终止码

}

 

 

此时makefile中去掉main

 

hello:hello.cc

        g++ $^ -o $@ -I ~/third_part/include

            -L ~/third_part/lib -lgtest -lpthread

.PHONY:clean

clean:

        rm hello

例题二、对求绝对值进行简单的单元测试:

.cc

 

# include<cstdio>

//实现一个求绝对值的函数

int Abs(int x){

    return x>0?x:-x;

}

//以下代码为测试代码

TEST(TestAbs,Positive)

{

//用法类似于assert宏:断言失败会(1)使程序崩溃,(2)进程异常终止:

//(3)会调用abort函数,导致进程异常终止。assert的使用方式比较单一

//ASSERT_TRUE宏的使用方法类似,但是更加灵活,失败时会导致:由原亮色变为红色

//通过框架会展示是否通过,通过的有哪些。

    ASSERT_TRUE(Abs(10)==10);

}

TEST(TestAbs,Positive)

{

    ASSERT_TRUE(Abs(-10)==10);

}

TEST(TestAbs,Positive)

{

    ASSERT_TRUE(Abs(0)==0);

}

Makefile:

 

main:main.cc

        g++ $^ -o $@ -I ~/third_part/include -L ~/third_part/lib

            -lgtest -lgtest_main -lpthread     

.PHONY:clean

clean:

        rm main

 

增加日志打印失败的值:ASSERT_TRUE(Abs(10)==10)<<”Abs(10)= “<<Abs(10);使用的运算符为移位运算符;断言失败会打印值。

ASSERT_TRUE:判断是否为真

ASSERT_EQ(值1,值2);判断两个值是否相等

ASSERT这样的致命断言,一旦失败,该TEST宏中的代码就不继续执行;EXPECT前缀的是非致命的断言,一旦失败,该TEST宏中的代码还能继续执行。ASSERT应用于:需求是实现一个测试文件的格式,用ASSERT来校验打开文件失败(文件打开失败,不能完成文件内容的验证);打开成功用EXPECT校验当前行格式是否正确。

哪个项目中应用到了这个知识点?

C_string :C语言风格的字符串以\0结尾的字符串

3、gtest中的事件机制:gtest在执行之前会有一个回调函数的时间,结束时又会有一定的时间用来销毁数据。

(1)库和框架的区别:

库:C++的标准库包含了标准模板库,STL是标准模板库。许多内容属于标准库而不是STL中的内容。库都是由程序员决定什么时机进行调用的。

框架:对于一些函数的调用时机不是由程序员自己来决定,而是由框架来决定。有些规则需要自己来定制,但是什么时候被调用不受程序员控制。

(2)事件:让事件得到进一步精简,使代码得到进一步重用。

例子:

# include<iostream>
# include<gtest/gtest.h>
# include<map>

void MakeMap(std::map<int,int>& test_map){
    test_map.insert(std::make_pair(1,1));
    test_map.insert(std::make_pair(2,1));
    test_map.insert(std::make_pair(3,1));
    test_map.insert(std::make_pair(4,1));
    test_map.insert(std::make_pair(5,1));

}
//需求是,针对std::map一些典型接口进行单元测试
TEST(TestMap,size){
    std::map<int,int>test_map;
    //插入数据:不允许插入key相同的数据
    MakeMap(test_map);
//进行测试
    ASSERT_EQ(test_map.size(),5);
}
TEST(TestMap,find){
   std::map<int,int>test_map;
    auto it=test_map.find(2);
    MakeMap(test_map);
    ASSERT_NE(it,test_map.end());
}
TEST(TestMap,operator){
   std::map<int,int>test_map;
   test_map[2]=100;
    MakeMap(test_map);
    ASSERT_EQ(test_map[2],100);
}

 

太繁琐,我们把共用的代码放入宏中,要使用时,自动调用:TEST_F搭配事件机制使用,测试函数的第一个参数名字必须相同,才能构成事件机制自动调用。

 

# include<iostream>
# include<gtest/gtest.h>
# include<map>
//通过虚函数的方式,将这样的自定制逻辑注册到框架中,框架自动决定什么时候执行。
class TestMap:public testing::Test{
public:
void setup(){
    test_map.insert(std::make_pair(1,1));
    test_map.insert(std::make_pair(2,1));
    test_map.insert(std::make_pair(3,1));
    test_map.insert(std::make_pair(4,1));
    test_map.insert(std::make_pair(5,1));

}
void TearDown(){
    test_map.clear();
}
std::map<int,int> test_map;
};
//需求是,针对std::map一些典型接口进行单元测试
TEST_F(TestMap,size){
    std::map<int,int>test_map;
//进行测试
    ASSERT_EQ(test_map.size(),5);
}
TEST_F(TestMap,find){
   std::map<int,int>test_map;
    auto it=test_map.find(2);
    ASSERT_NE(it,test_map.end());
}
TEST_F(TestMap,operator){
   std::map<int,int>test_map;
   test_map[2]=100;
    ASSERT_EQ(test_map[2],100);
}

 makefile:

main:main.cc
    g++ $^ -o $@ -I ~/third_part/include -L ~/third_part/lib\
        -lgtest -lgtest_main -lpthread -std=c++11
.PHONY:clean
clean:
    rm main

 

通过多态完成一个框架,向框架中插入数据:

 

posted on 2018-08-24 12:57  众里寻他2018  阅读(2495)  评论(0)    收藏  举报

导航