日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 人文社科 > 生活经验 >内容正文

生活经验

Google Test(GTest)使用方法和源码解析——自定义输出技术的分析和应用

發(fā)布時間:2023/11/27 生活经验 21 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Google Test(GTest)使用方法和源码解析——自定义输出技术的分析和应用 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

? ? ? ? 在介紹自定義輸出機(jī)制之前,我們先了解下AssertResult類型函數(shù)。(轉(zhuǎn)載請指明出于breaksoftware的csdn博客)

在函數(shù)中使用AssertionResult

? ? ? ??AssertionResult只有兩種類型:

  1. AssertionSuccess()
  2. AssertionFailure()

? ? ? ? 要么成功,要么失敗,我們就可以使用基礎(chǔ)斷言來判斷

::testing::AssertionResult IsEven(int n) {if ((n % 2) == 0)return ::testing::AssertionSuccess() << n << " is even";elsereturn ::testing::AssertionFailure() << n << " is odd";
}TEST(TestAssertResult, Check) {EXPECT_FALSE(IsEven(0));EXPECT_TRUE(IsEven(1));
}

? ? ? ? 我們在IsEven函數(shù)中輸出了額外的內(nèi)容(Actual中),便于我們之后查看結(jié)果

Value of: IsEven(0)Actual: true (0 is even)
Expected: false
error: Value of: IsEven(1)Actual: false (1 is odd)
Expected: true

自定義輸出斷言

? ? ? ? 如果默認(rèn)的輸出結(jié)果不能滿足我們的需要,或者我們的類型不支持字符流輸出,我們就需要自定義輸出。我們可以使用

Fatal assertionNonfatal assertionVerifies
ASSERT_PRED_FORMAT1(pred_format1, val1);EXPECT_PRED_FORMAT1(pred_format1, val1);pred_format1(val1) is successful
ASSERT_PRED_FORMAT2(pred_format2, val1, val2);EXPECT_PRED_FORMAT2(pred_format2, val1, val2);pred_format2(val1, val2) is successful
.........

? ? ? ? 這一系列GTest也是有5對函數(shù),最高是ASSERT/EXPECT_PRED_FORMAT5。我們看下使用的例子

::testing::AssertionResult IsEven2(const char* expr, int n) {if ((n % 2) == 0)return ::testing::AssertionSuccess() << expr << " = " << n << " is even";elsereturn ::testing::AssertionFailure() << expr << " = " << n << " is odd";
}TEST(TestAssertResult, Check2) {int a = 0;int b = 1;EXPECT_PRED_FORMAT1(IsEven2, a);EXPECT_PRED_FORMAT1(IsEven2, b);
}

? ? ? ? 我們發(fā)現(xiàn),用于判斷的表達(dá)式要求返回類型是AssertionResult。因為源碼底層是

#define GTEST_ASSERT_(expression, on_failure) \GTEST_AMBIGUOUS_ELSE_BLOCKER_ \if (const ::testing::AssertionResult gtest_ar = (expression)) \; \else \on_failure(gtest_ar.failure_message())

? ? ? ? 其次要求用于判斷的表達(dá)式第一個參數(shù)要是一個const char*類型數(shù)據(jù),它用于傳遞參數(shù)的名字。于是上面的測試輸出是

error: b = 1 is odd

自定義類型輸出

? ? ? ? 一些情況下,我們自定義類型可能是個復(fù)雜的符合結(jié)構(gòu)。C++編譯器并不知道怎么輸出它,這個時候我們就需要告訴GTest如何去輸出了。目前有兩種方式

定義輸出運(yùn)算符函數(shù)

? ? ? ? 比如待測類是class Bar。我們只要定義一個方法

::std::ostream& operator<<(::std::ostream& os, const Bar& bar) {return os << bar.DebugString();  // whatever needed to print bar to os
}

? ? ? ? 通過Bar暴露出來的方法將該對象輸出。我們看一個例子

#include <vector>
#include <string>
using namespace std;
class Bar {class Data {public:Data() {strData = "17";intData = 11;}public:std::string strData;int intData;};
public :std::string DebugString() const {std::string output = "Bar.Data.strData = ";output += data.strData;output += "\t";output += "Bar.Data.intData = ";char intBuffer[16] = {0};itoa(data.intData, intBuffer, 10);output += string(intBuffer);return output;}Data data;
};::std::ostream& operator<<(::std::ostream& os, const Bar& bar) {return os << bar.DebugString();  // whatever needed to print bar to os
}bool IsCorrectBarIntVector(vector<pair<Bar, int> > bar_ints) {return false;
}TEST(TestSelfDefineOutput, Test1) {vector<pair<Bar, int> > bar_ints;Bar bar;bar_ints.push_back(pair<Bar, int>(bar, 1));EXPECT_TRUE(IsCorrectBarIntVector(bar_ints))<< "bar_ints = " << ::testing::PrintToString(bar_ints);
}

? ? ? ? 我們將Bar設(shè)計為一個較為復(fù)雜的結(jié)構(gòu),然后定義了一個函數(shù)DebugString用于輸出其包含的變量。我們讓斷言進(jìn)入出錯狀態(tài),查看其輸出

  Actual: false
Expected: true
bar_ints = { (Bar.Data.strData = 17     Bar.Data.intData = 11, 1) }

? ? ? ? 可以看出來,GTest將Vector類型的數(shù)據(jù)格式化輸出(使用了PrintToString方法),并使用我們自定義DebugString輸出了自定義結(jié)構(gòu)。

? ? ? ? 這兒有個有趣的地方,PrintToString的實現(xiàn),比如它是如何判斷它是個容器的

template <typename T>
void PrintTo(const T& value, ::std::ostream* os) {DefaultPrintTo(IsContainerTest<T>(0), is_pointer<T>(), value, os);
}
typedef int IsContainer;
template <class C>
IsContainer IsContainerTest(int /* dummy */,typename C::iterator* /* it */ = NULL,typename C::const_iterator* /* const_it */ = NULL) {return 0;
}typedef char IsNotContainer;
template <class C>
IsNotContainer IsContainerTest(long /* dummy */) { return '\0'; }

? ? ? ? 編譯器遇到這種情況時,會試著用返回IsContainer的方法去匹配方法,但是如何發(fā)現(xiàn)class C沒有迭代器,則用返回IsNotContaner的函數(shù)取匹配。這樣就可以區(qū)分模板類是否是容器了。
? ? ? ? 還有個一is_pointer模板方法,用于判斷是否是指針。

template <typename T>
struct is_pointer : public false_type {};template <typename T>
struct is_pointer<T*> : public true_type {};

? ? ? ? 在我們的測試?yán)又?#xff0c;由于數(shù)據(jù)是個容器,且不是指針。那么將會匹配到

template <typename C>
void DefaultPrintTo(IsContainer /* dummy */,false_type /* is not a pointer */,const C& container, ::std::ostream* os) {

? ? ? ? 其實DefaultPrintTo方法還有其他兩個,只是本次沒有匹配到

template <typename T>
void DefaultPrintTo(IsNotContainer /* dummy */,true_type /* is a pointer */,T* p, ::std::ostream* os) {
template <typename T>
void DefaultPrintTo(IsNotContainer /* dummy */,false_type /* is not a pointer */,const T& value, ::std::ostream* os) {

定義PrintTo方法

? ? ? ? 有些時候,輸出運(yùn)算符可能被其他業(yè)務(wù)邏輯占用了。GTest就提供了一個針對性的方法,定義PrintTo方法,我們可以這么去做

void PrintTo(const Bar& bar, ::std::ostream* os) {*os << bar.DebugString();  // whatever needed to print bar to os
}

? ? ? ? 那么它在什么時候被調(diào)用的呢?PrintToString最終會調(diào)到如下的函數(shù)中,

template <typename C>
void DefaultPrintTo(IsContainer /* dummy */,false_type /* is not a pointer */,const C& container, ::std::ostream* os) {
......for (typename C::const_iterator it = container.begin();it != container.end(); ++it, ++count) {
......internal::UniversalPrint(*it, os);}
......
}
template <typename T1, typename T2>
void PrintTo(const ::std::pair<T1, T2>& value, ::std::ostream* os) {*os << '(';// We cannot use UniversalPrint(value.first, os) here, as T1 may be// a reference type.  The same for printing value.second.UniversalPrinter<T1>::Print(value.first, os);*os << ", ";UniversalPrinter<T2>::Print(value.second, os);*os << ')';
}
template <typename T>
class UniversalPrinter {public:GTEST_DISABLE_MSC_WARNINGS_PUSH_(4180)static void Print(const T& value, ::std::ostream* os) {PrintTo(value, os);}GTEST_DISABLE_MSC_WARNINGS_POP_()
};

? ? ? ? 其中UniversalPrinter<T1>::Print(value.first, os)會被我們定義的PrintTo匹配到,從而被調(diào)用。

總結(jié)

以上是生活随笔為你收集整理的Google Test(GTest)使用方法和源码解析——自定义输出技术的分析和应用的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。