gtest學習
- gtest
-
- gtest下載下傳編譯
- gtest導入工程
- 編寫測試單元用的宏(類似于函數)
-
- 斷言
- 測試宏
- 事件機制
-
- TestCase事件
- TestSuit事件
- 全局事件
- 測試結果檔案
軟體開發完成後需要對代碼進行測試,生成測試報告,是以開始學習單元測試。本文基于QT和Linux進行學習。學習目的就是生成測試報告。整個學習過程主要圍繞“1.怎麼進行單元測試”、“2.怎麼生成測試過程的結果檔案”、“3.怎麼生成代碼覆寫率報告”。
1.使用gtest進行單元測試
2.gtest有生成測試報告,但是可讀性差
3.結合gcov和lcov生成可視化代碼覆寫率報告
靈活開發應該是測試驅動開發,應該先有測試才有功能函數。
gtest
使用gtest應該先看一下gtest官方文檔,官方文檔對如何使用gtest描述得挺清楚。
gtest資源下載下傳連結。
gtest下載下傳編譯
//gtest依賴gcc 5.0+,檢視本地gcc版本
gcc -v
//下載下傳gtest資源後解壓
unzip googletest-main
//解壓後進入解壓檔案夾
mkdir build
cd build
cmake ..
make
編譯成功後,在解壓檔案夾/bulid/lib/中生成了需要用到的庫(檔案字尾*.a,後面需要添加到工程中),在解壓檔案夾/googlemock/include/,解壓檔案夾/googletest/include/内的檔案後面也需要添加到工程中。
gtest導入工程
gtest導入工程處理首先将上面提到的三個目錄複制到工程目錄下,然後需要将gtest所在的目錄資訊添加到CMakeLists.txt中。
# 第一,要添加這個GoogleTest requires at least C++14
set(CMAKE_CXX_STANDARD 14)
#第二,增加googletest/include/的絕對路徑
include_directories(
添加googletest/include/的目錄絕對路徑
)
#第三, 增加googletest/lib/的目錄絕對路徑
link_directories(
添加googletest/lib/的目錄絕對路徑
)
#第四,增加庫的名字
target_link_libraries (工程名
gtest gtest_main
-lpthread -lm ##pthread庫(Google Test使用了這個庫是以需要)
)
添加儲存完後,在終端
#在build目錄下
ccmake .. 或 cmake ..
#成功後就編譯
make
編寫測試單元用的宏(類似于函數)
斷言
基本斷言可以分為兩類,一類是ASSERT系列,一類是EXPECT系列。
- ASSERT_系列的斷言(Fatal assertion):當檢查點失敗時,退出目前函數(注意:并非退出目前案例)。一個TEST代表一個案例或測試用例
- EXPECT_系列的斷言(Nonfatal assertion):當檢查點失敗時,繼續執行下一個檢查點(每一個斷言表示一個檢查點)。
通常情況應該首選使用EXPECT_*,因為ASSERT_*在報告完錯誤後不會進行清理工作,有可能導緻記憶體洩露問題。
其中"<<"輸出錯誤時自定義的log資訊。例:
更多常用的斷言描述可參考gtest單元測試架構介紹及簡單使用
不常用但重要的斷言 | 斷言名 | 參數意義 |
---|---|---|
*_PRED* | EXPECT_PRED1(pred,val1) | pred:傳回值為bool的函數,此函數參數隻有一個,寫函數名就好。 val1:此函數傳的參數 |
*_PRED*斷言與*_TRUE斷言相似,但在失敗時*_PRED*斷言能列印更詳細的資訊 | EXPECT_PRED2(pred,val1,val2) | pred:傳回值為bool的函數,此函數參數為兩個,寫函數名就好。 val1:此函數傳的參數1,val2:此函數傳的參數2 |
ASSERT_PRED1(pred,val1) | 規則同上 | |
ASSERT_PRED2(pred,val1,val2) | 規則同上 | |
後續将繼續補充其他斷言… |
測試宏
測試宏分三類:TEST宏、TEST_F宏、TEST_P宏
TEST宏:
TEST(自定義命名,自定義命名),第一個參數testsuit名,相同的命名代表 同一個testsuit;第二個參數testcase名,測試案例名。這兩個參數根據實際設計的測試用例進行命名。
TEST_F宏:
TEST_F(測試類的名字,自定義命名),第一個參數代表testsuit名,相同的命名代表同一個testsuit;第二個參數testcase名,測試案例名。結合測試類使用。
TEST_P宏:
TEST_P(測試類的名字,自定義命名),第一個參數代表testsuit名,相同的命名代表同一個testsuit;第二個參數testcase名,測試案例名。結合測試類和參數生成。
注:TEST與TEST_F的差別是,當需要測試案例之間共享參數時,需要定義一個繼承testing::Test的類,TEST不能調用類,但TEST_F可以
例如:
class myTesting: public testing::TestWithParam<int>
{
public:
static void SetUpTestCase()//testsuit
{
cout<<"SetUpTestCase"<<endl;
}
static void TearDownTestCase()//testsuit
{
cout<<"TearDownTestCase"<<endl;
}
virtual void SetUp()//testcase
{
cout<<"SetUp"<<endl;
}
virtual void TearDown()
{
cout<<"TearDown"<<endl;
}
}
//生成參數
INSTANTIATE_TEST_SUITE_P(Param,myTesting,testing::Values(1,3,5,7));
/*測試參數:
* Range(begin,end,step)
* ValuesIn(begin,end)
* Bool()
* combine(,,,)排列組合
*/
TEST_P(myTesting,test)
{
int n = GetParam();
EXPECT_EQ(n,3)<<"inequal num "<<n;
}
事件機制
TestCase事件
- 在每個案例執行前後
- 需要多次對類初始時使用
- string有多個方法
- 适用情況:一個類,有多個行為。執行先後順序相關的
- 需要繼承testing::Test
- 代表一個測試用例
-
TestCase事件是挂在每個案例執行前後的,實作方式和Test’Suites的幾乎一樣,不過需要實作的是SetUp方法和TearDown方法:
1. SetUp()方法在每個TestCase之前執行。
2. TearDown()方法在每個TestCase之後執行。
TestSuit事件
- 在某一批案例中,第一個執行前到最後一個執行後
- 一般用于類行為測試或者其他有聯系的多個方法測試
- 适用情況:多個類,多個函數,有多種組合,用一個變量儲存整個過程
- 繼承testing::Test
- 在某一批測試用例中生命周期中唯一
需要寫一個類,繼承testing::Test,然後實作兩個靜态方法 1. SetUpTestCase() 方法在第一個TestCase之前執行。 2. TearDownTestCase() 方法在最後一個TestCase之後執行。
全局事件
所有案例執行前後
可用于組合類行為測試
需要有main函數:testing::AddGlobalTestEnvironment(new 全局測試類名)
testing::InitGoogleTest(&argc, argv);
繼承testing::Environment
整個所有測試用例中有效
測試結果檔案
- 終端輸出測試結果
...
[----------] 1 test from FooTest
[ RUN ] FooTest.DoesAbc
[ OK ] FooTest.DoesAbc
[----------] 2 tests from BarTest
[ RUN ] BarTest.HasXyzProperty
[ OK ] BarTest.HasXyzProperty
[ RUN ] BarTest.ReturnsTrueOnSuccess
... some error messages ...
[ FAILED ] BarTest.ReturnsTrueOnSuccess
...
[==========] 30 tests from 14 test suites ran.
[ PASSED ] 28 tests.
[ FAILED ] 2 tests, listed below:
[ FAILED ] BarTest.ReturnsTrueOnSuccess
[ FAILED ] AnotherTest.DoesXyz
2 FAILED TESTS
- 生成xml報告
//在main中增加下面代碼,會生成 項目名.xml
testing::GTEST_FLAG(output)="xml:";
xml内容如下
<?xml version="1.0" encoding="UTF-8"?>
<testsuites tests="3" failures="1" errors="0" time="0.035" timestamp="2011-10-31T18:52:42" name="AllTests">
<testsuite name="MathTest" tests="2" failures="1" errors="0" time="0.015">
<testcase name="Addition" file="test.cpp" line="1" status="run" time="0.007" classname="">
<failure message="Value of: add(1, 1)
 Actual: 3
Expected: 2" type="">...</failure>
<failure message="Value of: add(1, -1)
 Actual: 1
Expected: 0" type="">...</failure>
</testcase>
<testcase name="Subtraction" file="test.cpp" line="2" status="run" time="0.005" classname="">
</testcase>
</testsuite>
<testsuite name="LogicTest" tests="1" failures="0" errors="0" time="0.005">
<testcase name="NonContradiction" file="test.cpp" line="3" status="run" time="0.005" classname="">
</testcase>
</testsuite>
</testsuites>
下一篇學習内容是“怎麼生成代碼覆寫率報告”和“測試代碼和功能代碼隔離開”