gTest詳解

1. 安裝使用

1.1 安裝

在https://code.google.com/p/googletest/ 下載源碼
進入msvc, 注意編譯方式, 若是是dll, 選擇 gtest-md
編譯生成lib文件, 而後引入.文件便可使用git

1.2 使用

#include "gtest/gtest.h"
int _tmain(int argc, _TCHAR* argv[])
{
    testing::InitGoogleTest(&argc, argv);
    return RUN_ALL_TESTS();
}

固然咱們也能夠輸出到xmlgithub

int _tmain(int argc, _TCHAR* argv[])
{
    testing::GTEST_FLAG(output) = "xml:";
    testing::InitGoogleTest(&argc, argv);
    return RUN_ALL_TESTS();
}

2. 斷言

斷言的宏能夠分爲兩類ASSERT系列和EXPECT系列。函數

TEST(StringCmpTest, Demo)
{
    EXPECT_EQ(3, add(1, 2));
    ASSERT_EQ(3, add(1, 2));
}

咱們再來看下所支持的宏測試

  • ASSERT_EQ
  • ASSERT_NE
  • ASSERT_LE
  • ASSERT_LT
  • ASSERT_GE
  • ASSERT_GT

  • EXPECT_EQ
  • EXPECT_NE
  • EXPECT_LE
  • EXPECT_LT
  • EXPECT_GE
  • EXPECT_GT

  • ASSERT_TRUE
  • ASSERT_FALSE

  • ASSERT_STREQ
  • ASSERT_STRNE
  • ASSERT_STRCASEEQ
  • ASSERT_STRCASENE

  • ASSERT_FLOAT_EQ
  • ASSERT_DOUBLE_EQ

直接返回成功仍是失敗google

  • FAIL();
  • ADD_FAILURE();

Predicate Assertions指針

在使用EXPECT_TRUE或ASSERT_TRUE時,有時但願可以輸出更加詳細的信息,好比檢查一個函數的返回值TRUE仍是FALSE時,但願可以輸出傳入的參數是什麼,以便失敗後好跟蹤。所以提供了以下的斷言:code

  • ASSERT_PRED1(pred1, val1);
  • ASSERT_PRED2(pred2, val1, val2);

若是對這樣的輸出不滿意的話,還能夠自定義輸出格式化orm

  • ASSERT_PRED_FORMAT1(pred_format1, val1);`
  • ASSERT_PRED_FORMAT2(pred_format2, val1, val2);

例子

若是咱們有這樣一個類Arithmetic
咱們只須要新建一個ArithmeticUnit.cpp文件,而後寫下以下代碼:xml

#include "stdafx.h"
#include "Arithmetic.h"
#include "gtest/gtest.h"

TEST(Arithmetic, add){
    Arithmetic arith;
    int a(1), b(2);
    EXPECT_EQ(3, arith.add(1, 2));
}

3. 深刻解析gTest

首先從TEST宏入手, 咱們看下宏的定義對象

//1
 define TEST(test_case_name, test_name) GTEST_TEST(test_case_name, test_name)

//2
#define GTEST_TEST(test_case_name, test_name)\
GTEST_TEST_(test_case_name, test_name, \
          ::testing::Test, ::testing::internal::GetTestTypeId())

//3
#define GTEST_TEST_(test_case_name, test_name, parent_class, parent_id)\
class GTEST_TEST_CLASS_NAME_(test_case_name, test_name) : public parent_class {\
public:\
    GTEST_TEST_CLASS_NAME_(test_case_name, test_name)() {}\
private:\
    virtual void TestBody();\
    static ::testing::TestInfo* const test_info_ GTEST_ATTRIBUTE_UNUSED_;\
    GTEST_DISALLOW_COPY_AND_ASSIGN_(\
    GTEST_TEST_CLASS_NAME_(test_case_name, test_name));\
....

因此
1. 最終展開的宏是繼承自testing::Test類
2. 咱們最終寫的代碼是放在TestBody()中的
3. 經過靜態變量test_info_,調用MakeAndRegisterTestInfo對測試案例進行註冊。

看下MakeAndRegisterTestInfo 是如何實現的

TestInfo* MakeAndRegisterTestInfo(
    const char* test_case_name,
    const char* name,
    const char* type_param,
    const char* value_param,
    TypeId fixture_class_id,
    SetUpTestCaseFunc set_up_tc,
    TearDownTestCaseFunc tear_down_tc,
    TestFactoryBase* factory) {
  TestInfo* const test_info =
      new TestInfo(test_case_name, name, type_param, value_param,
                   fixture_class_id, factory);
  GetUnitTestImpl()->AddTestInfo(set_up_tc, tear_down_tc, test_info);
  return test_info;
}

TestInfo對象主要用於包含以下信息:

  1. 測試案例名稱(testcase name)
  2. 測試名稱(test name)

  3. 該案例是否須要執行

  4. 執行案例時,用於建立Test對象的函數指針
  5. 測試結果

咱們還看到,TestInfo的構造函數中,很是重要的一個參數就是工廠對象
internal::TestFactoryBase* factory
它主要負責在運行測試案例時建立出Test對象

new ::testing::internal::TestFactoryImpl<\
        GTEST_TEST_CLASS_NAME_(test_case_name, test_name)>)

咱們再來看下 TestFactoryImpl 是如何實現的

template <class TestClass>
class TestFactoryImpl : public TestFactoryBase {
 public:
  virtual Test* CreateTest() { return new TestClass; }
};

我靠, 這也能算是工廠嗎~

不過總之流程是, 咱們要建立一個測試對象的時候,先調用factory的CreateTest()方法 建立TestInfo對象, 再經過 GetUnitTestImpl()->AddTestInfo(set_up_tc, tear_down_tc, test_info);對TestInfo對象進行註冊

UnitTest 是單例
UnitTestImpl 是實現

void AddTestInfo(Test::SetUpTestCaseFunc set_up_tc,
               Test::TearDownTestCaseFunc tear_down_tc,
               TestInfo * test_info) {
// 獲取或建立了一個TestCase對象,並將testinfo添加到TestCase對象中。
GetTestCase(test_info->test_case_name(),
            test_info->test_case_comment(),
            set_up_tc,
            tear_down_tc)->AddTestInfo(test_info);
}

這裏TestCase對象就出來了

  1. TEST宏中的兩個參數,第一個參數testcase_name,就是TestCase對象的名稱,第二個參數test_name就是Test對象的名稱。而TestInfo包含了一個測試案例的一系列信息。

  2. 一個TestCase對象對應一個或多個TestInfo對象。

總結一下gtest裏的幾個關鍵的對象:

  1. UnitTest 單例,總管整個測試,包括測試環境信息,當前執行狀態等等
  2. Test 咱們本身編寫的,或經過TEST,TEST_F等宏展開後的Test對象,管理着測試案例的先後事件,具體的執行代碼TestBody。
  3. TestCase 測試案例對象,管理着基於TestCase的先後事件,管理內部多個TestInfo。
  4. TestInfo 管理着測試案例的基本信息,包括Test對象的建立方法。

一個簡單的UML圖以下

4. 擼一個山寨的

擼了一個山寨的,https://github.com/sld666666/TestUnit

相關文章
相關標籤/搜索