基於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

 

通過多態完成一個框架,向框架中插入數據:

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM