天天看點

Linux 單元測試學習過程 (1)——gtestgtest

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)&#x0A;  Actual: 3&#x0A;Expected: 2" type="">...</failure>
      <failure message="Value of: add(1, -1)&#x0A;  Actual: 1&#x0A;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>
           

下一篇學習内容是“怎麼生成代碼覆寫率報告”和“測試代碼和功能代碼隔離開”

繼續閱讀