Gtest 测试指导 入门基础(A)
Gtest 測試指導 入門基礎(A)
Table of Contents
? 1 Gtest的基本使用,包括下載,安裝,編譯。
o 1.1 下載
o 1.2 編譯
? 1.2.1 Gtest靜態庫的編譯
? 1.2.2 Gtest在VS中的編譯
? 2 在項目中配置Gtest
o 2.1 Gtest在非VS環境下的配置
o 2.2 Gtest在VS環境下的配置
? 3 Gtest的使用
o 3.1 Makefile
o 3.2 構建代碼
o 3.3 Gtest斷言的使用
o 3.4 Gtest的異常檢查
o 3.5 Gtest的事件機制
o 3.6 Gtest的參數化
o 3.7 Gtest的死亡測試
? 3.7.1 *_DEATH(statement, regex)
? 3.7.2 *_EXIT(statement, predicate, regex)
? 3.7.3 死亡測試運行方式
? 3.7.4 死亡測試的注意事項
o 3.8 Gtest的運行參數
? 4 作業
o 4.1 編寫一個DemoContainer類,按以下接口要求實現:
? 5 參考文獻
1 Gtest的基本使用,包括下載,安裝,編譯。
1.1 下載
直接在google中搜索gtest,第一個就是。也可以從下面地址下載gtest。
https://code.google.com/p/googletest/downloads/
1.2 編譯
1.2.1 Gtest靜態庫的編譯
在下載解壓后,假設你把gtest源碼放在/usr/src/gtest
GTEST_DIR=/usr/src/gtest
設置完GTEST_DIR之后,執行下列的命令
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中的編譯
下載解壓后,里面有個msvc目錄,使用VS的同學可以直接的打開msvc里面的工 程文件,打開后會提示你升級,升級后,我們直接編譯里面的“gtest”工程, 可以直接編過去的。最好是編譯Debug和Relese兩個版本。
這里需要注意的是:如果你升級gtest是在VS2008中升級,那么你要使用 gtest 進行測試的demo最好也是VS2008工程,不然你會發現很郁悶,你的 demo怎么也編不過。
如果你編譯了Debug和Relese兩個版本之后,在msvc里面就有兩個文件夾 Debug和Release,這兩個目錄中能看到編譯出來的gtestd.lib或gtest.lib文 件。
2 在項目中配置Gtest
2.1 Gtest在非VS環境下的配置
2.2 Gtest在VS環境下的配置
假設我們是用VS2010對gtest進行的編譯,那么我們的這個例子也要在VS2010 中建立。
創建我們要測試的Demo,在VS2010中創建一個空項目,命名為GtestMoney。 接下來為GtestMoney項目配置gtest環境。
3 Gtest的使用
下面將介紹在非VS環境下如何使用Gtest,我們將要用一個money的例子來展開 對Gtest的學習。
3.1 Makefile
一般的項目要有一個頭文件一個cpp文件還有一個測試文件,我們分別命名為 Money.h, Money.cpp和MoneyTest.cpp.因為我們要使用到Gtest,所以添加一 個Makefile來連接Gtest到我們的工程中。Makefile的內容如下。
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)
現在就可以在我們的Money工程中使用Gtest了。
3.2 構建代碼
首先我們就要開始寫一個測試用例來測試我們的money能否實例化成功。
// 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;
}
這段測試代碼是測試一個實例money是否創建成功,money的amount和currency是 否與我們創建實例初始化的值是相同的。
而此時執行命令"make"進行編譯肯定報錯,因為我們還沒有Money這個類也沒有接 口函數getAmount()和getCurrency()。所以我們要根據測試用例來補充我們的 Money類。
根據測試用例我們知道,Money類要有一個getAmount()這個功能要得到成員 amount。還有一個getCurrency()得到成員currency,而成員amount和currency通 過Money的構造函數進行初始化。所以接下來在我們的代碼中實現這部分功能。
//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;
}
這時編譯(make)還是編譯不過,因為我們沒有運行所有的測試用例。那我們用什 么運行測試呢?在MoneyTest.cpp的main函數中添加"RUN_ALL_TESTS()"意思是: 運行所有測試案例。
// file MoneyTest.cpp
int main(int argc, char** argv)
{
}
這個時候編譯(make)就會通過。但是執行的時候(make test)會產生下面的錯誤:
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
通過錯誤我們可以看到需要在MoneyTest.cpp的main函數中加入 testing::InitGoogleTest 所以我們需要繼續修改MoneyTest.cpp中的main:
// file MoneyTest.cpp
int main(int argc, char** argv)
{
testing::InitGoogleTest(&argc, argv);
return RUN_ALL_TESTS();
}
這時我們make編譯成功。運行money_unittest.exe會有如下輸出:
好,到目前為止我們已經完成了Gtest的環境的搭配和基本的構建使用。下面就來 具體的學習一下Gtest針對不同情況的測試吧。
3.3 Gtest斷言的使用
上面就是一個簡單的測試案例。這個我們使用了TEST這個gtest包裝好的宏, 它有兩個參數,官方的解釋:#define TEST(test_case_name, test_name) GTEST_TEST(test_case_name, test_name)。
對檢查點的檢查,我們上面使用到了EXPECT_EQ和EXPECT_STREQ這兩個宏, 其中EXPECT_EQ這個宏用來比較兩個數值是否相等。 EXPECT_STREQ(expected_str, actual_str)是比較兩個C字符串內容(同時 支持char* 和 wchar_t*).
Gtest采用了大量的宏來包裝斷言,此斷言不同于C語言的斷言(assert),按照 使用方法分為兩類:
EXPECT_* 系列斷言失敗時,案例繼續往下執行。
ASSERT_* 系列斷言失敗時,退出當前函數,ASSERT_*后面的代碼不會被 執行.(注意:并不是退出當前案例)
在上面的列子中為了我們的案例能夠運行起來我們在main函數中添加如下代 碼:
testing::InitGoogleTest(&argc, argv);
因為gtest的測試用例允許接收一系列的命令行參數因此我們在 "testing::InitGoogleTest(&argc, argv);"中將命令行參數傳給gtest, gtest的命令行參數非常的豐富,有興趣的大家可以自己查閱資料詳細的了解 一下。
下面我們添加一個新的斷言:
// 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;
}
會出現什么結果呢?
這樣的結果將會產生!這是因為EXPECT_EQ第一個參數是我們期望的結果是數值 555,而實際的結果是123.456,這與我們的期望不同,所以會有error產生。
值得注意的是在"EXPECT_EQ(555, money.getAmount())“出現error之后仍然繼 續執行輸出"Code after EXPECT!”.
如果我們期望結果數值不是實際函數的結果數值,那么就用下面的語句。
EXPECT_NE(555, money.getAmount());
這個時候所有的測試就會通過了!
讓我們再加上一個ASSERT_*系列的斷言,來體會ASSERT與EXPECT區別。
// file MoneyTest.cpp
// Assert test
TEST(MoneyConstructorTest, TestConstructorAssert)
{
// Set up
const std::string currencyBB(“ASSERT”);
const double longNumber = 222.222;
}
運行結果是
在ASSERT失敗之后, 語句"Code after ASSERT"沒有出現! 所以我們注意,最好不要在ASSERT語句后面做釋放內存等操作!
現在我們只是依照Money的功能和功能對應的測試用例添加了Money類的構造函數 和接口getAmount(), getCurrency的源碼,剩下的接口分別是operator ==, operator != 和 operator +=,大家可以按照想好功能,為功能添加測試用例, 補充功能源碼的方式來完成對以上三個未完成的接口的測試。下面是參考代碼:
// 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)書寫出對這些函數接口 的測試相應的測試。
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
數值型數據比較
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) 兩個C字符串內容相同(同時支持char *和wchart *類型)
ASSERT_STRNE(str1, str2) EXPECT_STRNE(str1, str2) 兩個C字符串內容不同(同時支持char *和wchart *類型)
ASSERT_STRCASEEQ(str1,str2) EXPECT_STRCASEEQ(str1,str2) 兩個C字符串內容相同,忽略大小寫(只支持char *類型)
ASSERT_STRCASENE(str1,str2) EXPECT_STRCASENE(str1,str2) 兩個C字符串內容不同,忽略大小寫(只支持char *類型)
浮點數比較
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
近似數比較
ASSERT_NEAR(val1, val2, abs_error) EXPECT_NEAR(val1, val2, abs_error 兩個數值val1和val2的 絕對值差不超過 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) 不拋異常
函數值與參數檢查(目前最多只支持5個參數)
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
自定義格式函數與參數檢查(目前最多支持5個參數)
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能夠檢測異常狀態,異常檢查一般用到的是 ASSERT_THROW/EXPECT_THROW。那么我們就來增加一個異常檢查的測試。
// file MoneyTest.cpp
TEST(MoneyThrowTest, ThrowTest)
{
// Set up
const Money money123AA(123, “AA”);
}
那么現在的輸出結果是:
MoneyThrowTest.ThrowTest顯示的狀態是通過,證明已經有異常拋出,測試用例 通過。
3.5 Gtest的事件機制
在開始gtest的事件機制之前,我們需要了解一個概念:測試固件!
很多時候,我們想在不同的測試執行前創建相同的配置環境,在測試執行結束后 執行相應的清理工作,測試固件(Test Fixture)為這種需求提供了方便。在單 元測試中,Fixture的作用是為測試創建輔助性的上下文環境,實現測試的初始化 和終結與測試過程本身的分離,便于不同測試使用相同代碼來搭建固定的配置環 境。用體操比賽的說法,測試過程體現了特定測試的自選動作,測試固件則體現 了對一系列測試(在開始和結束時)的規定動作。有些講單元測試的書籍直接把 測試固件稱為Scaffolding(腳手架)。使用測試固件比單純調用TEST宏稍微麻煩 一些:
每個帶固件的測試的執行順序是:
Gtest提供了多種事件機制方便在測試用例之前或者完成以后進行一些操作,
通過這些操作,我們可以在各個測試用例之前共享一些通用方法,共享資源。使 我們的用例更加的簡潔,清晰。Gtest的事件機制按照使用方法分為3類:
下面我們就分別介紹這3類事件的用法:
? 全局事件
必須通過繼承testing::Environment類,實現里面的SetUp和TearDown方 法:
在我們的MoneyTest.cpp中添加一個此事件的代碼是:
// file MoneyTest.cpp
class MoneyTestEnvironment : public testing::Environment
{
public:
virtual void SetUp()
{
std::cout << “Money Golbal Event SetUp.” << std::endl;
}
};
完成繼承類方法實現以后,還需要告訴gtest添加全局事件,我們需要在main函數 中通過testing::AddGlobalTestEnvironment方法添加該全局事件。如果需要增加 全局事件,也可以寫多個繼承類,然后將事件都添加到測試用例之前。
int main(int argc, char** argv)
{
// Add the global test environment
testing::AddGlobalTestEnvironment(new MoneyTestEnvironment);
}
運行的結果是:
從結果中我們可以看到Setup()在所有測試用例開始之前就自動被調用,而 TearDown()是在所有測試用例執行之后被調用。所以一些全局的資源初始化放在 SetUp()中,全局的資源回收放在TearDown()中。
? TestSuite事件
在某些情況下,我們可能不需要在整個全局的范圍內有一些共享而需要在各個測 試間共享一個相同的環境來保存和傳遞狀態,或者環境的狀態是只讀的,可以只 初始化一次,再或者創建環境的過程開銷很高,要求只初始化一次。共享某個固 件環境的所有測試合稱為一個“測試套件”(Test Suite),gtest中利用靜態成 員變量和靜態成員函數實現這個概念:
特別注意:
在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宏的第一個參數必須是上面繼承testing::test的繼承類名字 (MoneySuiteEventTest)。
運行的結果是:
從輸出可以看出SetUpTestCase()是在SuitTestCaseOne之前調用而 TearDownTestCase()是在SuiteTestCaseTwo后調用。
? TestCase事件
與TestSuite事件實現方法相同,需要通過繼承testing::Test類,但是只需 要實現里面的SetUp和TearDown兩個方法
在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;
}
運行的結果是
3.6 Gtest的參數化
在設計測試案例時,經常需要考慮給被測函數傳入不同的值的情況,以前的做 法一般是寫一個通用方法,然后編寫在測試案例調用它,即使使用了通用方法, 也需要很多重復性的工作。以下是一般的測試方法,如果需要測試N個數字, 則需要拷貝復制粘貼N次.
Gtest在這里提供了一個靈活的函數參數化測試的方案:
在MoneyTest.cpp中Gtest的參數化代碼是:
// 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));
運行的結果是:
Gtest中除了上面testing::Values()數據生成器之外,還有一系列的參數生成器:
Gtest中的參數生成器
Range(begin, end[, step]) 范圍在begin~end之間,步長為step,不包括end
Values(v1, v2, …, vN) v1,v2到vN的值
ValuesIn(container) and ValuesIn(begin, end) 從一個C類型的數組或是STL容器,或是迭代器中取值
Bool() 取false 和 true 兩個值
Combine(g1, g2, …, gN) 這個比較強悍,它將g1,g2,…gN進行排列組合,g1,g2,…gN本身是一個參數生成器,每次分別從g1,g2,…gN中各取出一個值,組合成一個元組(Tuple)作為一個參數。說明:這個功能只在提供了<tr1/tuple>頭的系統中有效。gtest會自動去判斷是否支持tr/tuple,如果你的系統確實支持,而gtest判斷錯誤的話,你可以重新定義宏GTEST_HAS_TR1_TUPLE=1。
除了測試用例可以參數化以外,gtest還提供了針對各種不同類型數據時的方案, 以及參數化類型的方案
// 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;
}
運行結果:
3.7 Gtest的死亡測試
“死亡測試”名字比較恐怖,這里的“死亡”是指程序的崩潰。通常在測試過 程中,我們需要考慮各種各樣的輸入,有的輸入可能直接導致程序崩潰,這時 我們就需要檢查程序是否按照預期的方式掛掉,這也就是所謂的“死亡測試”。 gtest的死亡測試能做到在一個安全的環境下執行崩潰的測試案例,同時又對 崩潰結果進行驗證
死亡測試宏定義
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下的不同。 簡單來說,通過*_DEATH(statement, regex) 和*_EXIT(statement, predicate, regex),我們可以非常方便的編寫導致崩潰 的測試案例,并且在不影響其他案例執行的情況下,對崩潰案例的結果進行檢 查。 以下是*DEATH用法介紹:
// file: MoneyTest.cpp
// Death Test
TEST(MoneyDeathTest, DeathTest)
{
// Set up
Money moneyAA(123.456, “DeathTestOne”);
Money moneyBB(0.123456, “DeathTestTwo”);
}
死亡測試的結果是:
從運行的結果我們可以看到"死亡測試"是第一個被執行的測試!
3.7.2 *_EXIT(statement, predicate, regex)
? 1. statement
? 2. predicate 在這里必須是一個委托,接收int型參數,并返回bool。只有當返回值為true時,死亡測試案例才算通過。
gtest提供了一些常用的predicate:
? 3. regex是一個正則表達是,用來匹配異常時在stderr中輸出的內容。
在POSIX系統(Linux, Cygwin, 和 Mac)中,gtest的死亡測試中使用的是 POSIX風格的正則表達式,想了解POSIX風格表達式可參考:
在Windows系統中,gtest的死亡測試中使用的是gtest自己實現的簡單的正 則表達式語法。 相比POSIX風格,gtest的簡單正則表達式少了很多內容, 比如 (“x|y”), ("(xy)"), ("[xy]") 和(“x{5,7}”)都不支持。
3.7.3 死亡測試運行方式
? 1. fast方式(默認方式)
? testing::FLAGS_gtest_death_test_style = “fast”;
? threadsafe方式
? testing::FLAGS_gtest_death_test_style = “threadsafe”;
你可以在 main() 里為所有的死亡測試設置測試形式,也可以為某次測試單 獨設置。Google Test會在每次測試之前保存這個標記并在測試完成后恢復, 所以你不需要去管這部分工作 。如:
int main(int argc, char** argv)
{
// Add the global test environment
testing::AddGlobalTestEnvironment(new MoneyTestEnvironment);
}
3.7.4 死亡測試的注意事項
3.8 Gtest的運行參數
使用gtest編寫的測試案例通常本身就是一個可執行文件,因此運行起來非常 方便。同時,gtest也為我們提供了一系列的運行參數(環境變量、命令行參 數或代碼里指定),使得我們可以對案例的執行進行一些有效的控制。gtest 提供了三種設置的途徑:
其優先級原則是,最后設置的那個會生效。通常情況下的優先級順序為: 命令行參數 > 代碼中指定FLAG > 系統環境變量。由于在gtest工程main函數 中,gtest通過testing::InitGoogleTest方法直接處理輸入參數,因此測試用 例可以處理命令行參數。
代碼:
// MoneyTest.cpp
int main(int argc, char** argv)
{
// Add the global test environment
testing::AddGlobalTestEnvironment(new MoneyTestEnvironment);
}
這樣就擁有了接收和響應gtest工程命令行參數的能力。如果需要在代碼中指定 FLAG,可以使用testing::GTESTFLAG這個宏來設置。比如相對于命令行參 數–gtest_output,可以使用testing::GTEST_FLAG(output) = “xml:”;來設置。 注意這里不需要加–gtest前綴了,同時,推薦將這句放置InitGoogleTest之前, 這樣就可以使得對于同樣的參數,命令行參數優先級高于代碼中指定。
// MoneyTest.cpp
int main(int argc, char** argv)
{
// Output farmat is XML
testing::GTEST_FLAG(output) = “xml:”;
}
如果需要gtest的設置系統環境變量,必須注意的是:
以下是所有命令行參數列表:
命令行參數 說明
–gtest_list_tests 使用這個參數時,將不會執行里面的測試案例,而是輸出一個案例的列表。
–gtest_filter 對執行的測試案例進行過濾,支持通配符 ? 單個字符 * 任意字符 - 排除,如-a 表示除了a : 取或,如a:b 表示a或b 比如下面的例子: ./foo_test 沒有指定過濾條件,運行所有案例; ./foo_test –gtest_filter=* 使用通配符*,表示運行所有案例; ./foo_test –gtest_filter=FooTest.* 運行所有“測試案例名稱(testcase_name)”為FooTest的案例; ./foo_test –gtest_filter=Null:Constructor 運行所有“測試案例名稱(testcase_name)”或“測試名稱(test_name)”包含Null或Constructor的案例; ./foo_test –gtest_filter=-DeathTest. 運行所有非死亡測試案例; ./foo_test –gtest_filter=FooTest.*-FooTest.Bar 運行所有“測試案例名稱(testcase_name)”為FooTest的案例,但是除了FooTest.Bar這個案例
–gtest_also_run_disabled_tests 執行案例時,同時也執行被置為無效的測試案例。關于設置測試案例無效的方法為:在測試案例名稱或測試名稱中添加DISABLED前綴。
–gtest_repeat=[COUNT] 設置案例重復運行次數: –gtest_repeat=1000:重復執行1000次,即使中途出現錯誤; –gtest_repeat=-1: 無限次數執行 –gtest_repeat=1000 –gtest_break_on_failure:重復執行1000次,并且在第一個錯誤發生時立即停止,這個功能對調試非常有用。 –gtest_repeat=1000 –gtest_filter=FooBar:重復執行1000次測試案例名稱為FooBar的案例。
命令行參數 說明
–gtest_color(yes/no/auto) 輸出命令行時是否使用一些五顏六色的顏色,默認是 auto。
–gtest_print_time 輸出命令行時是否打印每個測試案例的執行時間,默認是不打印的。
–gtest_output= xml[:DIRECTORYPATH/:FILEPA\TH] 將測試結果輸出到一個xml中。 –gtest_output=xml: 不指定輸出路徑時,默認為案例 當前路徑。 –gtest_output=xml:d:\ 指定輸出到某個目錄 –gtest_output=xml:d:\foo.xml 指定輸出到d:\foo.xml 如果不是指定了特定的文件路徑,gtest每次輸出的報告不會覆蓋,而會以數字后綴的方式創建
命令行參數 說明
–gtest_break_on_failure 調試模式下,當案例失敗時停止,方便調試。
–gtest_throw_on_failure 當案例失敗時以C++異常的方式拋出。
–gtest_catch_exceptions 是否捕捉異常。gtest默認是不捕捉異常的,因此假如測試案例拋了一個異常,很可能會彈出一個對話框,這非常的不友好,同時也阻礙了測試案例的運行。如果想不彈這個框,可以通過設置這個參數來實現。如將–gtest_catch_exceptions設置為一個非零的數。 注意:該參數只在Windows下有效。
以下是命令行參數列表在使用過程中遇到的一些問題總結:
到目前為止,我們已經掌握了Gtest常用的測試方法。Money例子的整體的 測試代碼參考如下:
// 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 作業
4.1 編寫一個DemoContainer類,按以下接口要求實現:
get_size函數的功能是得到這個"容器"的大小,也就是這個"容器"里所有元 素的數量,如果這個"容器"里沒有任何元素,那么返回0。
add_item 的作用是向"容器"中添加一個字符串元素。如果"容器"中已經存在 內容相同的元素,則添加失敗返回-1。如果添加成功,返回這個元素在"容器 "中對應的索引值。
get_item的作用是取得"容器"中索引為"index"的元素。如果參數"index"大 于(包括等于)當前"容器"中所有元素的數量,或者參數"index"是非正整數, 以上情況都拋出異常"out_of_range"。
remove_item的作用是移除"容器"中索引為"index"的元素。如果參數 "index"大于(包括等于)當前"容器"大小,或者參數"index"是非正整數,返回 “false”;否則刪除"容器"中對應索引為"index"的元素,并返回true。
大家根據提供的功能接口為接口來添加測試用例,再根據測試用例來完成功能的 代碼。 ·
5 參考文獻
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
總結
以上是生活随笔為你收集整理的Gtest 测试指导 入门基础(A)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: linux查看riak版本,Riak学习
- 下一篇: JavaScript 编程精解 中文第三