運用 Google Test 實作單元測試

 
實習目標 1. 安裝配合 Visual Studio 2010 或是 GNU g++ 的 Google Test

2. 了解 TEST() 巨集定義的 TestCase 與 Test 的運作架構

3. 了解 TEST_F() 巨集定義的 TestCase 與 Test, 以及由 ::testing::Test 衍生出來的 TestFixture 類別的運作架構

4. 運用 RUN_ALL_TESTS() 巨集來執行所有測試
   
步驟一

Google test 的全名是 Google C++ Testing Framework, 是 Google 根據 xUnit 架構開發出來的單元測試環境

支援的軟體平台: Linux, Mac OS X, Windows, Cygwin, Windows CE, and Symbian

目前運用這個單元測試環境的成功專案包括

同樣是和 JUnit, CppUnit 相同的 xUnit 架構, Google test 對一開始使用的人最大的好處是 使用方法較為簡化, 允許非致命性的錯誤

版本: 2013/09 gtest-1.7.0.zip (local copy), 2011/04 gtest-1.6.0.zip

安裝

請下載 gtest-1.7.0.zip, 解壓縮之後, 到 msvc\ 資料匣裡面點選專案檔 gtest.sln, Visual Studio 2010 會開啟它, 並且自動轉換為 visual sutdio 2010 的專案檔, 共有 gtest, gtest_main, gtest_prod_test, gtest_unitttest 四個專案

  1. 以右鍵選取 gtest 專案, 選擇建置, 會在 msvc\gtest\Debug\ 資料匣裡面產生 gtestd.lib, gtest_maind.lib gtest_prod_test.exe gtest_unittest.exe (其中 gtest_unittest.exe 以及 g_test_prod_test.exe 可以在 cmd 視窗中執行基本測試)

  2. 建置/組態管理員, 選取 Release, 以右鍵選取 gtest 專案, 選擇建置, 會在 msvc\gtest\Release\ 資料匣裡面產生 gtest.lib

    下面的動作是在 win7 64bit 系統上做的, 如果你是使用其他的系統, 要找到對應的資料匣

  3. 請將 gtest-1.7.0\include\ 資料匣中的整個 gtest 子資料匣拷貝到 C:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\include\ 中

  4. 請將 gtest-1.7.0\msvc\gtest\ 裡面 Release\gtest.lib, Debug\gtestd.lib 兩個檔案拷貝到 C:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\lib\ 資料匣中

googletest 在 code.google.com 上的網址為 https://code.google.com/p/googletest/

googletest 的參考資料請見 https://code.google.com/p/googletest/w/list

google test framework Primer, V1_5_Primer, V1_6_Primer 中文版 , V1_7_Primer

步驟二

基本運用概念

  1. 你需要針對你的應用程式的整體功能, 或是個別類別實現的功能, 撰寫測試程式碼: 一般不外乎設定一些變數或是物件的初始值, 透過應用程式系統的功能來改變變數的內容或是物件的狀態, 然後比對確認變數內容或是物件狀態是否合乎要求

  2. 每一個測試是一個函式, 類似功能的測試函式可以整合在一起放在同一個類別裡面, 這些測試常常也可以共用環境的初始化程序

  3. 最後把所有的測試以 TEST_F() 巨集表列後, 即可以巨集 RUN_ALL_TESTS() 執行所有測試
步驟三

設計整合多個測試的類別

ComplexMultiUnitTests.h

#include "gtest/gtest.h"  
#include "Complex.h"  
      
class ComplexMultiUnitTests: public ::testing::Test 
{  
protected:  
    ComplexMultiUnitTests() 
    {  
        // You can do set-up work for each test here.  
        cout << "\t[ComplexMultiUnitTests] Constructor..." << endl;  
    }  
  
    virtual ~ComplexMultiUnitTests() 
    {  
        // You can do clean-up work that doesn't throw exception here.  
        cout << "\t[ComplexMultiUnitTests] Deconstructor..." << endl;  
    }  
  
    // If the constructor and destructor are not enough for setting up  
    // and cleaning up each test, you can define the following methods.  
  
    // Code here will be called immediately after the constructor (right before each test)  
    virtual void SetUp();  
  
    // Code here will be called immediately after each test (right before the destructor)  
    virtual void TearDown();  
  
    // Objects declared here can be used by all tests in the test case for Complex.  
   
    Complex x1, x2, x3;
	
};  
	
ComplexMultiUnitTests.cpp

#include "ComplexMultiUnitTests.h"  
      
void ComplexMultiUnitTests::SetUp()  
{  
    cout << "\t[ComplexMultiUnitTests] Setup resources..." << endl;  
    x1.setValue(7, 3);	
    x2.setValue(2, 5);
    x3.setValue(5, -2);	
}  
      
void ComplexMultiUnitTests::TearDown()  
{  
    cout << "\t[ComplexMultiUnitTests] Teardown resources..." << endl;  
} 
步驟四

製作測試

TEST_F(ComplexMultiUnitTests, testAdd)  
{  
    x1.add(x2);
    Complex x4;
    x4.setValue(9,8);
    ASSERT_TRUE(x1.equal(x4,1e-10));
    EXPECT_EQ(x1.equal(x4,1e-10),1) ;
}


TEST_F(ComplexMultiUnitTests, testSubtract)  
{ 
    x1.subtract(x2);
    ASSERT_TRUE(x1.equal(x3,1e-10));
}


TEST_F(ComplexMultiUnitTests, testMultiply)  
{ 
    x2.multiply(x3);
    Complex x4;
    x4.setValue(20,21);
    ASSERT_TRUE(x4.equal(x2,1e-10));
}


TEST_F(ComplexMultiUnitTests, testDivide)  
{ 
    ASSERT_TRUE(x1.divide(x2));
    Complex x4;
    x4.setValue(1,-1);
    ASSERT_TRUE(x1.equal(x4,1e-10));
    x2.setValue(0, 0);
    ASSERT_TRUE(!x1.divide(x2));
}
步驟五 在 main 函式中運用 testing::InitGoogleTest 來處理命令列中 Google Test 特定的參數, 執行 RUN_ALL_TESTS()
#include "gtest/gtest.h"

int main(int argc, char** argv)  
{ int iret;
testing::InitGoogleTest(&argc, argv);
iret = RUN_ALL_TESTS(); system("pause"); return iret;
} 測試的結果如下 [==========] Running 4 tests from 1 test case.
[----------] Global test environment set-up.
[----------] 4 tests from ComplexMultiUnitTests
[ RUN ] ComplexMultiUnitTests.testAdd
[ComplexMultiUnitTests] Constructor...
[ComplexMultiUnitTests] Setup resources...
[ComplexMultiUnitTests] Teardown resources...
[ComplexMultiUnitTests] Deconstructor...
[ OK ] ComplexMultiUnitTests.testAdd (0 ms)
[ RUN ] ComplexMultiUnitTests.testMultiply
[ComplexMultiUnitTests] Constructor...
[ComplexMultiUnitTests] Setup resources...
[ComplexMultiUnitTests] Teardown resources...
[ComplexMultiUnitTests] Deconstructor...
[ OK ] ComplexMultiUnitTests.testMultiply (0 ms)
[ RUN ] ComplexMultiUnitTests.testDivide
[ComplexMultiUnitTests] Constructor...
[ComplexMultiUnitTests] Setup resources...
[ComplexMultiUnitTests] Teardown resources...
[ComplexMultiUnitTests] Deconstructor...
[ OK ] ComplexMultiUnitTests.testDivide (0 ms)
[ RUN ] ComplexMultiUnitTests.testSubtract
[ComplexMultiUnitTests] Constructor...
[ComplexMultiUnitTests] Setup resources...
[ComplexMultiUnitTests] Teardown resources...
[ComplexMultiUnitTests] Deconstructor...
[ OK ] ComplexMultiUnitTests.testSubtract (0 ms)
[----------] 4 tests from ComplexMultiUnitTests (0 ms total)

[----------] Global test environment tear-down
[==========] 4 tests from 1 test case ran. (0 ms total)
[ PASSED ] 4 tests.

 
步驟六 專案的屬性設定
  1. '專案 > lab31 屬性頁 > 組態屬性 - C/C++ > 程式碼產生 > 執行階段程式庫 >
    多執行緒(/MT)'

  2. '專案 > lab31 屬性頁 > 組態屬性 - 連結器 > 輸入 > 其他相依性'.
    加入 'gtest.lib'

  3. '專案 > lab31 屬性頁 > 組態屬性 - 建置事件 > 建置後事件 > 命令列'.
    加入 "$(TargetPath)"
    '專案 > lab31 屬性頁 > 組態屬性 - 建置事件 > 建置後事件 > 描述'
    加入 'Unit Tests by Google Test ...'

 

C++ 物件導向程式設計課程 首頁

製作日期: 03/13/2013 by 丁培毅 (Pei-yih Ting)
E-mail: pyting@mail.ntou.edu.tw TEL: 02 24622192x6615
海洋大學 電機資訊學院 資訊工程學系 Lagoon