Gtest 测试指导 入门基础(A)
Gtest 測(cè)試指導(dǎo) 入門基礎(chǔ)(A)
Table of Contents
? 1 Gtest的基本使用,包括下載,安裝,編譯。
o 1.1 下載
o 1.2 編譯
? 1.2.1 Gtest靜態(tài)庫的編譯
? 1.2.2 Gtest在VS中的編譯
? 2 在項(xiàng)目中配置Gtest
o 2.1 Gtest在非VS環(huán)境下的配置
o 2.2 Gtest在VS環(huán)境下的配置
? 3 Gtest的使用
o 3.1 Makefile
o 3.2 構(gòu)建代碼
o 3.3 Gtest斷言的使用
o 3.4 Gtest的異常檢查
o 3.5 Gtest的事件機(jī)制
o 3.6 Gtest的參數(shù)化
o 3.7 Gtest的死亡測(cè)試
? 3.7.1 *_DEATH(statement, regex)
? 3.7.2 *_EXIT(statement, predicate, regex)
? 3.7.3 死亡測(cè)試運(yùn)行方式
? 3.7.4 死亡測(cè)試的注意事項(xiàng)
o 3.8 Gtest的運(yùn)行參數(shù)
? 4 作業(yè)
o 4.1 編寫一個(gè)DemoContainer類,按以下接口要求實(shí)現(xiàn):
? 5 參考文獻(xiàn)
1 Gtest的基本使用,包括下載,安裝,編譯。
1.1 下載
直接在google中搜索gtest,第一個(gè)就是。也可以從下面地址下載gtest。
https://code.google.com/p/googletest/downloads/
1.2 編譯
1.2.1 Gtest靜態(tài)庫的編譯
在下載解壓后,假設(shè)你把gtest源碼放在/usr/src/gtest
GTEST_DIR=/usr/src/gtest
設(shè)置完GTEST_DIR之后,執(zhí)行下列的命令
g++ -IGTESTDIR/include?I{GTEST_DIR}/include -IGTESTD?IR/include?I{GTEST_DIR} -c ${GTEST_DIR}/src/gtest-all.cc
ar -rv libgtest.a gtest-all.o
來生成libgtest.a。
1.2.2 Gtest在VS中的編譯
下載解壓后,里面有個(gè)msvc目錄,使用VS的同學(xué)可以直接的打開msvc里面的工 程文件,打開后會(huì)提示你升級(jí),升級(jí)后,我們直接編譯里面的“gtest”工程, 可以直接編過去的。最好是編譯Debug和Relese兩個(gè)版本。
這里需要注意的是:如果你升級(jí)gtest是在VS2008中升級(jí),那么你要使用 gtest 進(jìn)行測(cè)試的demo最好也是VS2008工程,不然你會(huì)發(fā)現(xiàn)很郁悶,你的 demo怎么也編不過。
如果你編譯了Debug和Relese兩個(gè)版本之后,在msvc里面就有兩個(gè)文件夾 Debug和Release,這兩個(gè)目錄中能看到編譯出來的gtestd.lib或gtest.lib文 件。
2 在項(xiàng)目中配置Gtest
2.1 Gtest在非VS環(huán)境下的配置
2.2 Gtest在VS環(huán)境下的配置
假設(shè)我們是用VS2010對(duì)gtest進(jìn)行的編譯,那么我們的這個(gè)例子也要在VS2010 中建立。
創(chuàng)建我們要測(cè)試的Demo,在VS2010中創(chuàng)建一個(gè)空項(xiàng)目,命名為GtestMoney。 接下來為GtestMoney項(xiàng)目配置gtest環(huán)境。
3 Gtest的使用
下面將介紹在非VS環(huán)境下如何使用Gtest,我們將要用一個(gè)money的例子來展開 對(duì)Gtest的學(xué)習(xí)。
3.1 Makefile
一般的項(xiàng)目要有一個(gè)頭文件一個(gè)cpp文件還有一個(gè)測(cè)試文件,我們分別命名為 Money.h, Money.cpp和MoneyTest.cpp.因?yàn)槲覀円褂玫紾test,所以添加一 個(gè)Makefile來連接Gtest到我們的工程中。Makefile的內(nèi)容如下。
Should change to your path which contain libgtest.a
GTEST_DIR=H:/work/myGtest
The dirtory which contain Money.h, Money.cpp, MoneyTest and Makefile
SRC_DIR=/cygdrive/h/work/Sample
LDFLAGS += -L(GTESTDIR)/lib?lgtest?lpthreadCXXFLAGS+=?c?g?Wall?Wextra?I(GTEST_DIR)/lib -lgtest -lpthread CXXFLAGS += -c -g -Wall -Wextra -I(GTESTD?IR)/lib?lgtest?lpthreadCXXFLAGS+=?c?g?Wall?Wextra?I(GTEST_DIR)/include
TARGET = money_unittest
OBJS = money.o gtestMoney.o
CC=g++
.PHONY: clean all test
All Google Test headers. Usually you shouldn’t change this
definition.
all: $(TARGET)
$(TARGET) : $(OBJS)
$(CC) $^ -o $@ $(LDFLAGS)
money.o : $(SRC_DIR)/Money.cpp $(SRC_DIR)/Money.h
$(CC) $(CXXFLAGS) $< -o $@
gtestMoney.o : $(SRC_DIR)/MoneyTest.cpp $(SRC_DIR)/Money.h
$(CC) $(CXXFLAGS) $< -o $@
clean:
rm -f $(TARGET) $(OBJS)
test: (TARGET)./(TARGET) ./(TARGET)./(TARGET)
現(xiàn)在就可以在我們的Money工程中使用Gtest了。
3.2 構(gòu)建代碼
首先我們就要開始寫一個(gè)測(cè)試用例來測(cè)試我們的money能否實(shí)例化成功。
// file:MoneyTest.cpp
TEST(MoneyConstructorTest, TestConstructor)
{
// Set up
const std::string currencyAA(“AA”);
const double longNumber = 123.456;
}
int main(int argc, char** argv)
{
return 0;
}
這段測(cè)試代碼是測(cè)試一個(gè)實(shí)例money是否創(chuàng)建成功,money的amount和currency是 否與我們創(chuàng)建實(shí)例初始化的值是相同的。
而此時(shí)執(zhí)行命令"make"進(jìn)行編譯肯定報(bào)錯(cuò),因?yàn)槲覀冞€沒有Money這個(gè)類也沒有接 口函數(shù)getAmount()和getCurrency()。所以我們要根據(jù)測(cè)試用例來補(bǔ)充我們的 Money類。
根據(jù)測(cè)試用例我們知道,Money類要有一個(gè)getAmount()這個(gè)功能要得到成員 amount。還有一個(gè)getCurrency()得到成員currency,而成員amount和currency通 過Money的構(gòu)造函數(shù)進(jìn)行初始化。所以接下來在我們的代碼中實(shí)現(xiàn)這部分功能。
//file:Money.h
#ifndef MONEY_H
#define MONEY_H
#include
#include
class Money
{
public:
Money( double amount, std::string currency )
: m_amount( amount )
, m_currency( currency )
{
}
double getAmount() const;
std::string getCurrency() const;
private:
double m_amount;
std::string m_currency;
};
#endif
// file Money.cpp
#include “Money.h”
double Money::getAmount() const
{
return m_amount;
}
std::string Money::getCurrency() const
{
return m_currency;
}
這時(shí)編譯(make)還是編譯不過,因?yàn)槲覀儧]有運(yùn)行所有的測(cè)試用例。那我們用什 么運(yùn)行測(cè)試呢?在MoneyTest.cpp的main函數(shù)中添加"RUN_ALL_TESTS()"意思是: 運(yùn)行所有測(cè)試案例。
// file MoneyTest.cpp
int main(int argc, char** argv)
{
}
這個(gè)時(shí)候編譯(make)就會(huì)通過。但是執(zhí)行的時(shí)候(make test)會(huì)產(chǎn)生下面的錯(cuò)誤:
lixiang@lixiang-PC /cygdrive/h/work/Sample
$ make test
./money_unittest
This test program did NOT call ::testing::InitGoogleTest before calling RUN_ALL_
TESTS(). Please fix it.
Makefile:36: recipe for target ‘test’ failed
make: *** [test] Error 1
通過錯(cuò)誤我們可以看到需要在MoneyTest.cpp的main函數(shù)中加入 testing::InitGoogleTest 所以我們需要繼續(xù)修改MoneyTest.cpp中的main:
// file MoneyTest.cpp
int main(int argc, char** argv)
{
testing::InitGoogleTest(&argc, argv);
return RUN_ALL_TESTS();
}
這時(shí)我們make編譯成功。運(yùn)行money_unittest.exe會(huì)有如下輸出:
好,到目前為止我們已經(jīng)完成了Gtest的環(huán)境的搭配和基本的構(gòu)建使用。下面就來 具體的學(xué)習(xí)一下Gtest針對(duì)不同情況的測(cè)試吧。
3.3 Gtest斷言的使用
上面就是一個(gè)簡(jiǎn)單的測(cè)試案例。這個(gè)我們使用了TEST這個(gè)gtest包裝好的宏, 它有兩個(gè)參數(shù),官方的解釋:#define TEST(test_case_name, test_name) GTEST_TEST(test_case_name, test_name)。
對(duì)檢查點(diǎn)的檢查,我們上面使用到了EXPECT_EQ和EXPECT_STREQ這兩個(gè)宏, 其中EXPECT_EQ這個(gè)宏用來比較兩個(gè)數(shù)值是否相等。 EXPECT_STREQ(expected_str, actual_str)是比較兩個(gè)C字符串內(nèi)容(同時(shí) 支持char* 和 wchar_t*).
Gtest采用了大量的宏來包裝斷言,此斷言不同于C語言的斷言(assert),按照 使用方法分為兩類:
EXPECT_* 系列斷言失敗時(shí),案例繼續(xù)往下執(zhí)行。
ASSERT_* 系列斷言失敗時(shí),退出當(dāng)前函數(shù),ASSERT_*后面的代碼不會(huì)被 執(zhí)行.(注意:并不是退出當(dāng)前案例)
在上面的列子中為了我們的案例能夠運(yùn)行起來我們?cè)趍ain函數(shù)中添加如下代 碼:
testing::InitGoogleTest(&argc, argv);
因?yàn)間test的測(cè)試用例允許接收一系列的命令行參數(shù)因此我們?cè)?"testing::InitGoogleTest(&argc, argv);"中將命令行參數(shù)傳給gtest, gtest的命令行參數(shù)非常的豐富,有興趣的大家可以自己查閱資料詳細(xì)的了解 一下。
下面我們添加一個(gè)新的斷言:
// file: MoneyTest.cpp
TEST(MoneyConstructorTest, TestConstructor)
{
// Set up
const std::string currencyAA(“AA”);
const double longNumber = 123.456;
// Process
Money money(longNumber, currencyAA);
// Check
EXPECT_EQ(longNumber, money.getAmount());
EXPECT_STREQ(“AA”, money.getCurrency().c_str());
EXPECT_EQ(555, money.getAmount());
std::cout << “Code after EXPECT!” << std::endl;
}
會(huì)出現(xiàn)什么結(jié)果呢?
這樣的結(jié)果將會(huì)產(chǎn)生!這是因?yàn)镋XPECT_EQ第一個(gè)參數(shù)是我們期望的結(jié)果是數(shù)值 555,而實(shí)際的結(jié)果是123.456,這與我們的期望不同,所以會(huì)有error產(chǎn)生。
值得注意的是在"EXPECT_EQ(555, money.getAmount())“出現(xiàn)error之后仍然繼 續(xù)執(zhí)行輸出"Code after EXPECT!”.
如果我們期望結(jié)果數(shù)值不是實(shí)際函數(shù)的結(jié)果數(shù)值,那么就用下面的語句。
EXPECT_NE(555, money.getAmount());
這個(gè)時(shí)候所有的測(cè)試就會(huì)通過了!
讓我們?cè)偌由弦粋€(gè)ASSERT_*系列的斷言,來體會(huì)ASSERT與EXPECT區(qū)別。
// file MoneyTest.cpp
// Assert test
TEST(MoneyConstructorTest, TestConstructorAssert)
{
// Set up
const std::string currencyBB(“ASSERT”);
const double longNumber = 222.222;
}
運(yùn)行結(jié)果是
在ASSERT失敗之后, 語句"Code after ASSERT"沒有出現(xiàn)! 所以我們注意,最好不要在ASSERT語句后面做釋放內(nèi)存等操作!
現(xiàn)在我們只是依照Money的功能和功能對(duì)應(yīng)的測(cè)試用例添加了Money類的構(gòu)造函數(shù) 和接口getAmount(), getCurrency的源碼,剩下的接口分別是operator ==, operator != 和 operator +=,大家可以按照想好功能,為功能添加測(cè)試用例, 補(bǔ)充功能源碼的方式來完成對(duì)以上三個(gè)未完成的接口的測(cè)試。下面是參考代碼:
// file Money.h
#ifndef MONEY_H
#define MONEY_H
#include
#include
class IncompatibleMoneyError : public std::runtime_error
{
public:
IncompatibleMoneyError() : std::runtime_error( “Incompatible moneys” )
{
}
};
class Money
{
public:
Money( double amount, std::string currency )
: m_amount( amount )
, m_currency( currency )
{
}
double getAmount() const;
std::string getCurrency() const;
bool operator ==( const Money &other ) const;
bool operator !=( const Money &other ) const;
Money &operator +=( const Money &other );
private:
double m_amount;
std::string m_currency;
};
#endif
// file Money.cpp
#include “Money.h”
double Money::getAmount() const
{
return m_amount;
}
std::string Money::getCurrency() const
{
return m_currency;
}
bool Money::operator ==( const Money &other ) const
{
return m_amount == other.m_amount &&
m_currency == other.m_currency;
}
bool Money::operator !=( const Money &other ) const
{
return !(*this == other);
}
Money & Money::operator +=( const Money &other )
{
if ( m_currency != other.m_currency )
throw IncompatibleMoneyError();
}
大家都可以用EXPECT_TRUE(FALSE)/ASSERT_TRUE(FALSE)書寫出對(duì)這些函數(shù)接口 的測(cè)試相應(yīng)的測(cè)試。
gtest的斷言按照常用功能依次分為12類,平常主要用到的是一下幾類:
|ASSERT_FALSE(condition) |EXPECT_TRUE(condition) |condition == false | |ASSERT_NE(val1, val2) | EXPECT_NE(val1, val2) | val1 != val2 |
布爾值比較
ASSERT_TRUE(condition) EXPECT_TRUE(condition) condition == true
數(shù)值型數(shù)據(jù)比較
ASSERT_EQ(expected, actual) EXPECT_EQ(expected, actual) expected == actual
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) val2 >= val2
字符串比較
ASSERT_STREQ(str1, str2) EXPECT_STREQ(str1, str2) 兩個(gè)C字符串內(nèi)容相同(同時(shí)支持char *和wchart *類型)
ASSERT_STRNE(str1, str2) EXPECT_STRNE(str1, str2) 兩個(gè)C字符串內(nèi)容不同(同時(shí)支持char *和wchart *類型)
ASSERT_STRCASEEQ(str1,str2) EXPECT_STRCASEEQ(str1,str2) 兩個(gè)C字符串內(nèi)容相同,忽略大小寫(只支持char *類型)
ASSERT_STRCASENE(str1,str2) EXPECT_STRCASENE(str1,str2) 兩個(gè)C字符串內(nèi)容不同,忽略大小寫(只支持char *類型)
浮點(diǎn)數(shù)比較
ASSERT_FLOAT_EQ(val1,val2) EXPECT_FLOAT_EQ(val1,val2) the two float values are almost equal
ASSERT_DOUBLE_EQ(val1,val2) EXPECT_DOUBLE_EQ(val1,val2) the two double values are almost equal
近似數(shù)比較
ASSERT_NEAR(val1, val2, abs_error) EXPECT_NEAR(val1, val2, abs_error 兩個(gè)數(shù)值val1和val2的 絕對(duì)值差不超過 abs_error
異常檢查
ASSERT_THROW(statement, exception_type) EXPECT_THROW(statement, exception_type) 拋出指定類型異常
ASSERT_THROW(statement) EXPECT_THROW(statement) 拋出任意類型異常
ASSERT_NO_THROW(statement) EXPECT_NO_THROW(statement) 不拋異常
函數(shù)值與參數(shù)檢查(目前最多只支持5個(gè)參數(shù))
ASSERT_PRED1(pred1, val1) EXPECT_PRED1(pred1, val1) pred1(val1) returns true
ASSERT_PRED2(pred2, val1,val2) EXPECT_PRED2(pred2, val1, val2) pred2(val1, val2) returns true
Windows HRESULT
ASSERT_HRESULT_SUCCEEDED (expression) EXPECT_HRESULT_SUCCEEDED (expression) expression is a success HRESULT
ASSERT_HRESULT_FAILED (expression) EXPECT_HRESULT_FAILED (expression) expression is a failure HRESUL
自定義格式函數(shù)與參數(shù)檢查(目前最多支持5個(gè)參數(shù))
ASSERT_PRED_FORMAT1(pred1, val1) EXPECT_PRED_FORMAT1(pred1, val1) pred1(val1) is successful
ASSERT_PRED_FORMAT1(pred1, val1, val2) EXPECT_PRED_FORMAT1(pred1, val1, val2) pred2(val1, val2) is successful
3.4 Gtest的異常檢查
通過上面的表格我們知道gtest能夠檢測(cè)異常狀態(tài),異常檢查一般用到的是 ASSERT_THROW/EXPECT_THROW。那么我們就來增加一個(gè)異常檢查的測(cè)試。
// file MoneyTest.cpp
TEST(MoneyThrowTest, ThrowTest)
{
// Set up
const Money money123AA(123, “AA”);
}
那么現(xiàn)在的輸出結(jié)果是:
MoneyThrowTest.ThrowTest顯示的狀態(tài)是通過,證明已經(jīng)有異常拋出,測(cè)試用例 通過。
3.5 Gtest的事件機(jī)制
在開始gtest的事件機(jī)制之前,我們需要了解一個(gè)概念:測(cè)試固件!
很多時(shí)候,我們想在不同的測(cè)試執(zhí)行前創(chuàng)建相同的配置環(huán)境,在測(cè)試執(zhí)行結(jié)束后 執(zhí)行相應(yīng)的清理工作,測(cè)試固件(Test Fixture)為這種需求提供了方便。在單 元測(cè)試中,Fixture的作用是為測(cè)試創(chuàng)建輔助性的上下文環(huán)境,實(shí)現(xiàn)測(cè)試的初始化 和終結(jié)與測(cè)試過程本身的分離,便于不同測(cè)試使用相同代碼來搭建固定的配置環(huán) 境。用體操比賽的說法,測(cè)試過程體現(xiàn)了特定測(cè)試的自選動(dòng)作,測(cè)試固件則體現(xiàn) 了對(duì)一系列測(cè)試(在開始和結(jié)束時(shí))的規(guī)定動(dòng)作。有些講單元測(cè)試的書籍直接把 測(cè)試固件稱為Scaffolding(腳手架)。使用測(cè)試固件比單純調(diào)用TEST宏稍微麻煩 一些:
每個(gè)帶固件的測(cè)試的執(zhí)行順序是:
Gtest提供了多種事件機(jī)制方便在測(cè)試用例之前或者完成以后進(jìn)行一些操作,
通過這些操作,我們可以在各個(gè)測(cè)試用例之前共享一些通用方法,共享資源。使 我們的用例更加的簡(jiǎn)潔,清晰。Gtest的事件機(jī)制按照使用方法分為3類:
下面我們就分別介紹這3類事件的用法:
? 全局事件
必須通過繼承testing::Environment類,實(shí)現(xiàn)里面的SetUp和TearDown方 法:
在我們的MoneyTest.cpp中添加一個(gè)此事件的代碼是:
// file MoneyTest.cpp
class MoneyTestEnvironment : public testing::Environment
{
public:
virtual void SetUp()
{
std::cout << “Money Golbal Event SetUp.” << std::endl;
}
};
完成繼承類方法實(shí)現(xiàn)以后,還需要告訴gtest添加全局事件,我們需要在main函數(shù) 中通過testing::AddGlobalTestEnvironment方法添加該全局事件。如果需要增加 全局事件,也可以寫多個(gè)繼承類,然后將事件都添加到測(cè)試用例之前。
int main(int argc, char** argv)
{
// Add the global test environment
testing::AddGlobalTestEnvironment(new MoneyTestEnvironment);
}
運(yùn)行的結(jié)果是:
從結(jié)果中我們可以看到Setup()在所有測(cè)試用例開始之前就自動(dòng)被調(diào)用,而 TearDown()是在所有測(cè)試用例執(zhí)行之后被調(diào)用。所以一些全局的資源初始化放在 SetUp()中,全局的資源回收放在TearDown()中。
? TestSuite事件
在某些情況下,我們可能不需要在整個(gè)全局的范圍內(nèi)有一些共享而需要在各個(gè)測(cè) 試間共享一個(gè)相同的環(huán)境來保存和傳遞狀態(tài),或者環(huán)境的狀態(tài)是只讀的,可以只 初始化一次,再或者創(chuàng)建環(huán)境的過程開銷很高,要求只初始化一次。共享某個(gè)固 件環(huán)境的所有測(cè)試合稱為一個(gè)“測(cè)試套件”(Test Suite),gtest中利用靜態(tài)成 員變量和靜態(tài)成員函數(shù)實(shí)現(xiàn)這個(gè)概念:
特別注意:
在MoneyTest.cpp中添加TestSuite事件的代碼如下:
// file MoneyTest.cpp
// Test Suite Event Test
class MoneySuiteEventTest : public testing::Test
{
public:
static void SetUpTestCase()
{
std::cout << “Money Test SuiteEventTest SetUpTestCase.” << std::endl;
}
};
TEST_F(MoneySuiteEventTest, SuiteTestCaseOne)
{
const std::string currencyCC(“SuiteTestCaseOne”);
const double longNumber = 123.456;
}
TEST_F(MoneySuiteEventTest, SuiteTestCaseTwo)
{
const std::string currencyCC(“SuiteTestCaseTwo”);
const double longNumber = 123.456;
}
特別注意使用TEST_F宏的第一個(gè)參數(shù)必須是上面繼承testing::test的繼承類名字 (MoneySuiteEventTest)。
運(yùn)行的結(jié)果是:
從輸出可以看出SetUpTestCase()是在SuitTestCaseOne之前調(diào)用而 TearDownTestCase()是在SuiteTestCaseTwo后調(diào)用。
? TestCase事件
與TestSuite事件實(shí)現(xiàn)方法相同,需要通過繼承testing::Test類,但是只需 要實(shí)現(xiàn)里面的SetUp和TearDown兩個(gè)方法
在MonyTest.cpp中TestCase事件的代碼是:
// file MoneyTest.cpp
// Test TestCase
class MoneyTestCaseTest : public testing::Test
{
public:
void SetUp()
{
std::cout << “Money Test MoneyTestCaseTest SetUp.” << std::endl;
}
};
TEST_F(MoneyTestCaseTest, TestCaseTestOne)
{
const std::string currencyDD(“TestCaseTestOne”);
const double longNumber = 123.456;
}
TEST_F(MoneyTestCaseTest, TestCaseTestTwo)
{
const std::string currencyDD(“TestCaseTestTwo”);
const double longNumber = 123.456;
}
運(yùn)行的結(jié)果是
3.6 Gtest的參數(shù)化
在設(shè)計(jì)測(cè)試案例時(shí),經(jīng)常需要考慮給被測(cè)函數(shù)傳入不同的值的情況,以前的做 法一般是寫一個(gè)通用方法,然后編寫在測(cè)試案例調(diào)用它,即使使用了通用方法, 也需要很多重復(fù)性的工作。以下是一般的測(cè)試方法,如果需要測(cè)試N個(gè)數(shù)字, 則需要拷貝復(fù)制粘貼N次.
Gtest在這里提供了一個(gè)靈活的函數(shù)參數(shù)化測(cè)試的方案:
在MoneyTest.cpp中Gtest的參數(shù)化代碼是:
// file MoneyTest.cpp
// Parameter Testing one
class MoneyParameterTest : public testing::TestWithParam
{
public:
};
TEST_P(MoneyParameterTest, ParameterTest)
{
double acount = GetParam();
Money money(acount, “Test”);
EXPECT_EQ(acount, money.getAmount());
}
INSTANTIATE_TEST_CASE_P(ParameterTest, MoneyParameterTest,
testing::Values(111.111, 222.2222, 333.3333, 444.44444));
運(yùn)行的結(jié)果是:
Gtest中除了上面testing::Values()數(shù)據(jù)生成器之外,還有一系列的參數(shù)生成器:
Gtest中的參數(shù)生成器
Range(begin, end[, step]) 范圍在begin~end之間,步長(zhǎng)為step,不包括end
Values(v1, v2, …, vN) v1,v2到vN的值
ValuesIn(container) and ValuesIn(begin, end) 從一個(gè)C類型的數(shù)組或是STL容器,或是迭代器中取值
Bool() 取false 和 true 兩個(gè)值
Combine(g1, g2, …, gN) 這個(gè)比較強(qiáng)悍,它將g1,g2,…gN進(jìn)行排列組合,g1,g2,…gN本身是一個(gè)參數(shù)生成器,每次分別從g1,g2,…gN中各取出一個(gè)值,組合成一個(gè)元組(Tuple)作為一個(gè)參數(shù)。說明:這個(gè)功能只在提供了<tr1/tuple>頭的系統(tǒng)中有效。gtest會(huì)自動(dòng)去判斷是否支持tr/tuple,如果你的系統(tǒng)確實(shí)支持,而gtest判斷錯(cuò)誤的話,你可以重新定義宏GTEST_HAS_TR1_TUPLE=1。
除了測(cè)試用例可以參數(shù)化以外,gtest還提供了針對(duì)各種不同類型數(shù)據(jù)時(shí)的方案, 以及參數(shù)化類型的方案
// file: MoneyTest.cpp
// Parameter Testing two
// Step one
template
class MoneyTemplateTest : public testing::Test
{
public:
typedef std::list List;
static T shared;
T value;
};
// Step two
typedef testing::Types<double, long double> MoneyTypes;
TYPED_TEST_CASE(MoneyTemplateTest, MoneyTypes);
// Step three
TYPED_TEST(MoneyTemplateTest, TemplateTest)
{
// Inside a test, refer to the special name TypeParam to get the type
// parameter. Since we are inside a derived class template, C++ requires
// us to visit the members of MoneyTemplateTest via ‘this’.
TypeParam n = this->value;
}
運(yùn)行結(jié)果:
3.7 Gtest的死亡測(cè)試
“死亡測(cè)試”名字比較恐怖,這里的“死亡”是指程序的崩潰。通常在測(cè)試過 程中,我們需要考慮各種各樣的輸入,有的輸入可能直接導(dǎo)致程序崩潰,這時(shí) 我們就需要檢查程序是否按照預(yù)期的方式掛掉,這也就是所謂的“死亡測(cè)試”。 gtest的死亡測(cè)試能做到在一個(gè)安全的環(huán)境下執(zhí)行崩潰的測(cè)試案例,同時(shí)又對(duì) 崩潰結(jié)果進(jìn)行驗(yàn)證
死亡測(cè)試宏定義
ASSERT_DEATH(statement, regex) EXPECT_DEATH(statement, regex) statement crashes with the given error
ASSERT_EXIT(statement, predicate, regex) EXPECT_EXIT(statement, predicate, regex) statement exits with the given error and its exit code matches predicate
3.7.1 _DEATH(statement, regex)
由于有些異常只在Debug下拋出,因此還提供了_DEBUGDEATH,用來處理 Debug和Realease下的不同。 簡(jiǎn)單來說,通過*_DEATH(statement, regex) 和*_EXIT(statement, predicate, regex),我們可以非常方便的編寫導(dǎo)致崩潰 的測(cè)試案例,并且在不影響其他案例執(zhí)行的情況下,對(duì)崩潰案例的結(jié)果進(jìn)行檢 查。 以下是*DEATH用法介紹:
// file: MoneyTest.cpp
// Death Test
TEST(MoneyDeathTest, DeathTest)
{
// Set up
Money moneyAA(123.456, “DeathTestOne”);
Money moneyBB(0.123456, “DeathTestTwo”);
}
死亡測(cè)試的結(jié)果是:
從運(yùn)行的結(jié)果我們可以看到"死亡測(cè)試"是第一個(gè)被執(zhí)行的測(cè)試!
3.7.2 *_EXIT(statement, predicate, regex)
? 1. statement
? 2. predicate 在這里必須是一個(gè)委托,接收int型參數(shù),并返回bool。只有當(dāng)返回值為true時(shí),死亡測(cè)試案例才算通過。
gtest提供了一些常用的predicate:
? 3. regex是一個(gè)正則表達(dá)是,用來匹配異常時(shí)在stderr中輸出的內(nèi)容。
在POSIX系統(tǒng)(Linux, Cygwin, 和 Mac)中,gtest的死亡測(cè)試中使用的是 POSIX風(fēng)格的正則表達(dá)式,想了解POSIX風(fēng)格表達(dá)式可參考:
在Windows系統(tǒng)中,gtest的死亡測(cè)試中使用的是gtest自己實(shí)現(xiàn)的簡(jiǎn)單的正 則表達(dá)式語法。 相比POSIX風(fēng)格,gtest的簡(jiǎn)單正則表達(dá)式少了很多內(nèi)容, 比如 (“x|y”), ("(xy)"), ("[xy]") 和(“x{5,7}”)都不支持。
3.7.3 死亡測(cè)試運(yùn)行方式
? 1. fast方式(默認(rèn)方式)
? testing::FLAGS_gtest_death_test_style = “fast”;
? threadsafe方式
? testing::FLAGS_gtest_death_test_style = “threadsafe”;
你可以在 main() 里為所有的死亡測(cè)試設(shè)置測(cè)試形式,也可以為某次測(cè)試單 獨(dú)設(shè)置。Google Test會(huì)在每次測(cè)試之前保存這個(gè)標(biāo)記并在測(cè)試完成后恢復(fù), 所以你不需要去管這部分工作 。如:
int main(int argc, char** argv)
{
// Add the global test environment
testing::AddGlobalTestEnvironment(new MoneyTestEnvironment);
}
3.7.4 死亡測(cè)試的注意事項(xiàng)
3.8 Gtest的運(yùn)行參數(shù)
使用gtest編寫的測(cè)試案例通常本身就是一個(gè)可執(zhí)行文件,因此運(yùn)行起來非常 方便。同時(shí),gtest也為我們提供了一系列的運(yùn)行參數(shù)(環(huán)境變量、命令行參 數(shù)或代碼里指定),使得我們可以對(duì)案例的執(zhí)行進(jìn)行一些有效的控制。gtest 提供了三種設(shè)置的途徑:
其優(yōu)先級(jí)原則是,最后設(shè)置的那個(gè)會(huì)生效。通常情況下的優(yōu)先級(jí)順序?yàn)?#xff1a; 命令行參數(shù) > 代碼中指定FLAG > 系統(tǒng)環(huán)境變量。由于在gtest工程main函數(shù) 中,gtest通過testing::InitGoogleTest方法直接處理輸入?yún)?shù),因此測(cè)試用 例可以處理命令行參數(shù)。
代碼:
// MoneyTest.cpp
int main(int argc, char** argv)
{
// Add the global test environment
testing::AddGlobalTestEnvironment(new MoneyTestEnvironment);
}
這樣就擁有了接收和響應(yīng)gtest工程命令行參數(shù)的能力。如果需要在代碼中指定 FLAG,可以使用testing::GTESTFLAG這個(gè)宏來設(shè)置。比如相對(duì)于命令行參 數(shù)–gtest_output,可以使用testing::GTEST_FLAG(output) = “xml:”;來設(shè)置。 注意這里不需要加–gtest前綴了,同時(shí),推薦將這句放置InitGoogleTest之前, 這樣就可以使得對(duì)于同樣的參數(shù),命令行參數(shù)優(yōu)先級(jí)高于代碼中指定。
// MoneyTest.cpp
int main(int argc, char** argv)
{
// Output farmat is XML
testing::GTEST_FLAG(output) = “xml:”;
}
如果需要gtest的設(shè)置系統(tǒng)環(huán)境變量,必須注意的是:
以下是所有命令行參數(shù)列表:
命令行參數(shù) 說明
–gtest_list_tests 使用這個(gè)參數(shù)時(shí),將不會(huì)執(zhí)行里面的測(cè)試案例,而是輸出一個(gè)案例的列表。
–gtest_filter 對(duì)執(zhí)行的測(cè)試案例進(jìn)行過濾,支持通配符 ? 單個(gè)字符 * 任意字符 - 排除,如-a 表示除了a : 取或,如a:b 表示a或b 比如下面的例子: ./foo_test 沒有指定過濾條件,運(yùn)行所有案例; ./foo_test –gtest_filter=* 使用通配符*,表示運(yùn)行所有案例; ./foo_test –gtest_filter=FooTest.* 運(yùn)行所有“測(cè)試案例名稱(testcase_name)”為FooTest的案例; ./foo_test –gtest_filter=Null:Constructor 運(yùn)行所有“測(cè)試案例名稱(testcase_name)”或“測(cè)試名稱(test_name)”包含Null或Constructor的案例; ./foo_test –gtest_filter=-DeathTest. 運(yùn)行所有非死亡測(cè)試案例; ./foo_test –gtest_filter=FooTest.*-FooTest.Bar 運(yùn)行所有“測(cè)試案例名稱(testcase_name)”為FooTest的案例,但是除了FooTest.Bar這個(gè)案例
–gtest_also_run_disabled_tests 執(zhí)行案例時(shí),同時(shí)也執(zhí)行被置為無效的測(cè)試案例。關(guān)于設(shè)置測(cè)試案例無效的方法為:在測(cè)試案例名稱或測(cè)試名稱中添加DISABLED前綴。
–gtest_repeat=[COUNT] 設(shè)置案例重復(fù)運(yùn)行次數(shù): –gtest_repeat=1000:重復(fù)執(zhí)行1000次,即使中途出現(xiàn)錯(cuò)誤; –gtest_repeat=-1: 無限次數(shù)執(zhí)行 –gtest_repeat=1000 –gtest_break_on_failure:重復(fù)執(zhí)行1000次,并且在第一個(gè)錯(cuò)誤發(fā)生時(shí)立即停止,這個(gè)功能對(duì)調(diào)試非常有用。 –gtest_repeat=1000 –gtest_filter=FooBar:重復(fù)執(zhí)行1000次測(cè)試案例名稱為FooBar的案例。
命令行參數(shù) 說明
–gtest_color(yes/no/auto) 輸出命令行時(shí)是否使用一些五顏六色的顏色,默認(rèn)是 auto。
–gtest_print_time 輸出命令行時(shí)是否打印每個(gè)測(cè)試案例的執(zhí)行時(shí)間,默認(rèn)是不打印的。
–gtest_output= xml[:DIRECTORYPATH/:FILEPA\TH] 將測(cè)試結(jié)果輸出到一個(gè)xml中。 –gtest_output=xml: 不指定輸出路徑時(shí),默認(rèn)為案例 當(dāng)前路徑。 –gtest_output=xml:d:\ 指定輸出到某個(gè)目錄 –gtest_output=xml:d:\foo.xml 指定輸出到d:\foo.xml 如果不是指定了特定的文件路徑,gtest每次輸出的報(bào)告不會(huì)覆蓋,而會(huì)以數(shù)字后綴的方式創(chuàng)建
命令行參數(shù) 說明
–gtest_break_on_failure 調(diào)試模式下,當(dāng)案例失敗時(shí)停止,方便調(diào)試。
–gtest_throw_on_failure 當(dāng)案例失敗時(shí)以C++異常的方式拋出。
–gtest_catch_exceptions 是否捕捉異常。gtest默認(rèn)是不捕捉異常的,因此假如測(cè)試案例拋了一個(gè)異常,很可能會(huì)彈出一個(gè)對(duì)話框,這非常的不友好,同時(shí)也阻礙了測(cè)試案例的運(yùn)行。如果想不彈這個(gè)框,可以通過設(shè)置這個(gè)參數(shù)來實(shí)現(xiàn)。如將–gtest_catch_exceptions設(shè)置為一個(gè)非零的數(shù)。 注意:該參數(shù)只在Windows下有效。
以下是命令行參數(shù)列表在使用過程中遇到的一些問題總結(jié):
// file: MoneyTest.cpp
#include
#include
#include <gtest\gtest.h>
#include “Money.h”
// EXPECT Testing
TEST(MoneyConstructorTest, TestConstructor)
{
// Set up
const std::string currencyAA(“AA”);
const double longNumber = 123.456;
}
// End EXPECT Testing
// ASSERT Testing
TEST(MoneyConstructorTest, TestConstructorAssert)
{
// Set up
const std::string currencyBB(“ASSERT”);
const double longNumber = 222.222;
}
// End ASSERT Testing
// Throw Testing
TEST(MoneyThrowTest, ThrowTest)
{
// Set up
const Money money123AA(123, “AA”);
}
// End Throw Testing
// Global Event Testing
class MoneyTestEnvironment : public testing::Environment
{
public:
virtual void SetUp()
{
std::cout << “Money Global Event SetUp.” << std::endl;
}
};
// End Global Event Testing
// Suite Event Testing
class MoneySuiteEventTest : public testing::Test
{
public:
static void SetUpTestCase()
{
std::cout << “Money Test SuiteEventTest SetUpTestCase.” << std::endl;
}
};
TEST_F(MoneySuiteEventTest, SuiteTestCaseOne)
{
const std::string currencyCC(“CC”);
const double longNumber = 123.456;
}
TEST_F(MoneySuiteEventTest, SuiteTestCaseTwo)
{
const std::string currencyCC(“DD”);
const double longNumber = 123.456;
}
// End Suite Event Testing
// TestCase Event Testing
class MoneyTestCaseTest : public testing::Test
{
public:
void SetUp()
{
std::cout << “Money Test MoneyTestCaseTest SetUp.” << std::endl;
}
};
TEST_F(MoneyTestCaseTest, TestCaseTestOne)
{
const std::string currencyDD(“TestCaseTestOne”);
const double longNumber = 123.456;
}
TEST_F(MoneyTestCaseTest, TestCaseTestTwo)
{
const std::string currencyDD(“TestCaseTestTwo”);
const double longNumber = 123.456;
}
// End TestCase Event Testing
// Parameter Testing one
class MoneyParameterTest : public testing::TestWithParam
{
public:
};
TEST_P(MoneyParameterTest, ParameterTest)
{
double acount = GetParam();
Money money(acount, “Test”);
EXPECT_EQ(acount, money.getAmount());
}
INSTANTIATE_TEST_CASE_P(ParameterTest, MoneyParameterTest,
testing::Values(111.111, 222.2222, 333.3333, 444.44444));
// End Parameter Testing one
// Parameter Extual Testing two
// Step one
template
class MoneyTemplateTest : public testing::Test
{
public:
typedef std::list List;
static T shared;
T value;
};
// Step two
typedef testing::Types<double, long double> MoneyTypes;
TYPED_TEST_CASE(MoneyTemplateTest, MoneyTypes);
// Step three
TYPED_TEST(MoneyTemplateTest, TemplateTest)
{
// Inside a test, refer to the special name TypeParam to get the type
// parameter. Since we are inside a derived class template, C++ requires
// us to visit the members of MoneyTemplateTest via ‘this’.
TypeParam n = this->value;
}
// End Parameter Extual Testing two
// Death Test
TEST(MoneyDeathTest, DeathTest)
{
// Set up
Money moneyAA(123.456, “DeathTestOne”);
Money moneyBB(0.123456, “DeathTestTwo”);
}
// End Death Test
int main(int argc, char** argv)
{
testing::GTEST_FLAG(output) = “xml:”;
}
4 作業(yè)
4.1 編寫一個(gè)DemoContainer類,按以下接口要求實(shí)現(xiàn):
get_size函數(shù)的功能是得到這個(gè)"容器"的大小,也就是這個(gè)"容器"里所有元 素的數(shù)量,如果這個(gè)"容器"里沒有任何元素,那么返回0。
add_item 的作用是向"容器"中添加一個(gè)字符串元素。如果"容器"中已經(jīng)存在 內(nèi)容相同的元素,則添加失敗返回-1。如果添加成功,返回這個(gè)元素在"容器 "中對(duì)應(yīng)的索引值。
get_item的作用是取得"容器"中索引為"index"的元素。如果參數(shù)"index"大 于(包括等于)當(dāng)前"容器"中所有元素的數(shù)量,或者參數(shù)"index"是非正整數(shù), 以上情況都拋出異常"out_of_range"。
remove_item的作用是移除"容器"中索引為"index"的元素。如果參數(shù) "index"大于(包括等于)當(dāng)前"容器"大小,或者參數(shù)"index"是非正整數(shù),返回 “false”;否則刪除"容器"中對(duì)應(yīng)索引為"index"的元素,并返回true。
大家根據(jù)提供的功能接口為接口來添加測(cè)試用例,再根據(jù)測(cè)試用例來完成功能的 代碼。 ·
5 參考文獻(xiàn)
http://www.cnblogs.com/coderzh/archive/2009/04/06/1426755.html
https://code.google.com/p/googletest/w/list
http://developer.51cto.com/art/201108/285290.htm
http://www.doc88.com/p-079433664365.html
Author: 于麗香 yu-lx@neusoft.com
Date: 2018-09-01 10:28:59 CST
HTML generated by org-mode 6.33x in emacs 23
總結(jié)
以上是生活随笔為你收集整理的Gtest 测试指导 入门基础(A)的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: linux查看riak版本,Riak学习
- 下一篇: select下拉框分组展示插件的使用--