博客目標:
1、搭建GTEST單元測試環境
2、對已有的一個項目進行單元測試,測試內容 函數、類的公/私有方法
單元測試開始之前,要先明確幾個基本的概念,GTEST的單元測試實際上就是再單獨創建一個工程,然後include待測試的函數/類,完成一些特定的測試功能,從這一點上來說,使用GTEST進行單元測試與自己創建空的工程調用待測函數完成一些測試功能是一樣的。GTEST的優點在於提供了一些有用的測試函數,讓我們在測試的時候不需要花費太多的精力去構造這些測試函數。
第一步,搭建GTEST測試環境
首先要到github上去下GTEST的源碼,GTEST倉庫地址,下載的時候注意分支的選擇以及版本的選擇,新的GTEST版本在早期的VS中是無法編譯的,我現在用的GTEST是v1.8.x分支中的release_1.7.0版本,VS用的是2008.
下載下來之後,找到上面紅框中的路徑,打開gest.sln這個解決方案,在VS中對整個方案進行debug以及release兩種方式的編譯,並將編譯的lib文件以及頭文件拷貝到一個你自己覺得引用起來方便的位置,以下是我的操作結果。
在測試工程的特性中單獨添加頭文件(c/c++ -general - addtional path)以及lib依賴(linker - input - addtioanl path),但是要注意的是添加lib的時候,路徑要寫到具體的文件名,如C:\gtestLib \gtestd.lib,否則也會找不到鏈接。
同時不要忘了修改這個玩意,忘了的話也會報一堆鏈接錯誤。
完成以上,就完成了GTEST的搭建。
第二步,對已經有的一個項目中的函數以及類進行單元測試。
上圖中,在sln中本身存在一個工程helloWorldForUnitest ,在工程中本身有addClass一個類,addFunc一個函數。爲了對這兩個文件中的內容進行測試,我又新建了一個unitTestDemo的工程,並在工程屬性-C/C++-general-addtional path中添加了helloWorldForUnitest中頭文件所在的路徑,以使測試工程能夠調用到待測函數,並右鍵add - an exist item添加了這兩個頭文件對應的cpp文件。
給出以上文件的代碼
addClass.h,聲明瞭一個類(聲明類的時候,類塊結束的時候一定要有分號做結尾,否則編譯時候會報:構造函數返回值錯誤),包含公有方法以及私有方法。
#ifndef ADDCLASS_H
#define ADDCLASS_H
#include "forcePublic.h"
class addClass{
public:
addClass();
~addClass();
int getInput(int a,int b);
int getResult();
private:
int addMethod(int a,int b);
private:
int ma;
int mb;
int mResult;
};
#endif
addClass.cpp,實現了上面文件中聲明的類。
#include "addClass.h"
#include <stdio.h>
addClass::addClass()
{
ma = 0;
mb = 0;
mResult = 0;
}
addClass::~addClass()
{
}
int addClass::getInput(int a,int b)
{
ma = a;
mb = b;
addClass::addMethod( a, b);
return 0;
}
int addClass::getResult()
{
return mResult;
}
int addClass::addMethod(int a,int b)
{
mResult = a + b;
return mResult;
}
forcePublic.h,一系列的宏定義用以完成測試過程中私有化方法轉成公有方法的功能,方便測試工程對類中的私有方法進行訪問。
#ifndef FORCEPUBLIC_H
#define FORCEPUBLIC_H
#define GTEST
#ifdef GTEST
#define private public
#define protected public
#endif
#endif
addFunc.h,聲明瞭一個方法
# ifndef ADDFUNC_H
# define ADDFUNC_H
int addFunc(int a,int b);
# endif
addFunc.cpp,實現了上面文件中聲明的方法
# include "addFunc.h"
int addFunc(int a,int b)
{
int c = a + b;
return c;
}
test1.cpp,用於對上面的類和方法進行測試
#include <gtest/gtest.h>
#include <tchar.h>
#include "addFunc.h"
#include "addClass.h"
int Foo(int a, int b)
{
if (a == 0 || b == 0)
{
throw "don't do that";
}
int c = a % b;
if (c == 0)
return b;
return Foo(b, c);
}
TEST(FooTest, HandleNoneZeroInput)
{
EXPECT_EQ(2, Foo(4, 10));
EXPECT_EQ(6, Foo(30, 18));
}
TEST(addFuncTest, HandleNoneZeroInput)
{
EXPECT_EQ(14, addFunc(4, 10));
EXPECT_EQ(48, addFunc(30, 18));
}
TEST(addClassTest,HandleNoneZeroInput)
{
int addorResult;
addClass addor;
addor.getInput(4,12);
addorResult = addor.getResult();
EXPECT_EQ(16,addorResult);
// private member test
EXPECT_EQ(100,addor.addMethod(1,99));
}
int _tmain(int argc, _TCHAR* argv[])
{
testing::InitGoogleTest(&argc, argv);
RUN_ALL_TESTS();
getchar();
return RUN_ALL_TESTS();
}
完成以上內容後,編譯unitTestDemo工程,然後調試得到以下運行結果,證明你的第一個GTEST單元測試成功了。
PS:補充一些GTEST函數原型
// ***************************API index************************************//
//-------------------------------------------------------------------------//
//Fatal assertion Nonfatal assertion Verifies
//ASSERT_TRUE(condition); EXPECT_TRUE(condition); condition is true
//ASSERT_FALSE(condition); EXPECT_FALSE(condition); condition is false
//------------------------------------------------------------------------//
//Fatal assertion Nonfatal assertion Verifies
//ASSERT_EQ(expected, actual); EXPECT_EQ(expected, actual); expected == actual
//ASSERT_NE(val1, val2); EXPECT_NE(val1, val2); val1 != val2
//ASSERT_LT(val1, val2); EXPECT_LT(val1, val2); val1 < val2
//ASSERT_LE(val1, val2); EXPECT_LE(val1, val2); val1 <= val2
//ASSERT_GT(val1, val2); EXPECT_GT(val1, val2); val1 > val2
//ASSERT_GE(val1, val2); EXPECT_GE(val1, val2); val1 >= val2
//------------------------------------------------------------------------//
//Fatal assertion Nonfatal assertion Verifies
//ASSERT_STREQ(expected_str, actual_str); EXPECT_STREQ(expected_str, actual_str); the two C strings have the same content
//ASSERT_STRNE(str1, str2); EXPECT_STRNE(str1, str2); the two C strings have different content
//ASSERT_STRCASEEQ(expected_str, actual_str); EXPECT_STRCASEEQ(expected_str, actual_str); the two C strings have the same content, ignoring case
//ASSERT_STRCASENE(str1, str2); EXPECT_STRCASENE(str1, str2); the two C strings have different content, ignoring case
//------------------------------------------------------------------------//
//Fatal assertion Nonfatal assertion Verifies
//ASSERT_THROW(statement, exception_type); EXPECT_THROW(statement, exception_type); statement throws an exception of the given type
//ASSERT_ANY_THROW(statement); EXPECT_ANY_THROW(statement); statement throws an exception of any type
//ASSERT_NO_THROW(statement); EXPECT_NO_THROW(statement); statement doesn't throw any exception
//
//class myTest : public::testing::TestWithParam<int> {
// };
//
// TEST_P(myTest, aLotTest) {
// int n = GetParam();
// EXPECT_TRUE(func (n));
// }
//
//INSTANTIATE_TEST_CASE_P(PreName, myTest, testing::Values(1, 10, 100, 1000, 10000));