A quick introduction to Google test
視頻參考:Google C++ Testing GTest GMock Framework
為什么要使用 Google C++ Testing Framework?
使用這個框架有許多好理由。本文討論其中幾個。
某些類型的測試有糟糕的內存問題,這些問題只在某幾次運行期間出現。Google 的測試框架為處理這種情況提供了出色的支持。可以使用 Google 框架重復運行相同的測試一千次。當出現故障的跡象時,自動地調用調試器。另外,這只需要在命令行上傳遞兩個開關即可實現:--gtest_repeat=1000 --gtest_break_on_failure。
與其他許多測試框架相反,可以把 Google 測試框架內置的斷言部署在禁用了異常處理(通常由于性能原因)的軟件中。因此,也可以在析構函數中安全地使用斷言。
運行測試很簡單。只需調用預定義的?RUN_ALL_TESTS?宏,而不需要通過創建或驅動單獨的運行器類來執行測試。這比 CppUnit 等框架方便多了。
只需傳遞一個開關即可生成 Extensible Markup Language (XML) 報告:?--gtest_output="xml:<file name>"。在 CppUnit 和 CppTest 等框架中,需要編寫很多代碼才能生成 XML 輸出。
創建基本測試
以下代碼均在Linux下運行。也可以利用VS2017?cross platform feature?在Windows本地進行Gtest測試。
sample.h
#ifndef _SAMPLE_H_ #define _SAMPLE_H_// Returns n! (the factorial of n). For negative n, n! is defined to be 1. int Factorial(int n);// Returns true iff n is a prime number. bool IsPrime(int n);#endif View Codesample.c
#include "sample.h"// Returns n! (the factorial of n). For negative n, n! is defined to be 1. int Factorial(int n) {int result = 1;for (int i = 1; i <= n; i++) {result *= i;}return result; }// Returns true iff n is a prime number. bool IsPrime(int n) {// Trivial case 1: small numbersif (n <= 1) return false;// Trivial case 2: even numbersif (n % 2 == 0) return n == 2;// Now, we have that n is odd and n >= 3.// Try to divide n by every odd number i, starting from 3for (int i = 3; ; i += 2) {// We only have to try i up to the square root of nif (i > n/i) break;// Now, we have i <= n/i < n.// If n is divisible by i, n is not prime.if (n % i == 0) return false;}// n has no integer factor in the range (1, n), and thus is prime.return true; } View Codesample_unittest.c
#include <limits.h> #include "sample.h" #include "gtest/gtest.h" namespace {TEST(FactorialTest, Negative) {// This test is named "Negative", and belongs to the "FactorialTest"// test case.EXPECT_EQ(1, Factorial(-5));EXPECT_EQ(1, Factorial(-1));EXPECT_GT(Factorial(-10), 0); }TEST(FactorialTest, Zero) {EXPECT_EQ(1, Factorial(0)); }TEST(FactorialTest, Positive) {EXPECT_EQ(1, Factorial(1));EXPECT_EQ(2, Factorial(2));EXPECT_EQ(6, Factorial(3));EXPECT_EQ(40320, Factorial(8)); }// Tests IsPrime() TEST(IsPrimeTest, Negative) {EXPECT_FALSE(IsPrime(-1));EXPECT_FALSE(IsPrime(-2));EXPECT_FALSE(IsPrime(INT_MIN)); }TEST(IsPrimeTest, Trivial) {EXPECT_FALSE(IsPrime(0));EXPECT_FALSE(IsPrime(1));EXPECT_TRUE(IsPrime(2));EXPECT_TRUE(IsPrime(3)); }TEST(IsPrimeTest, Positive) {EXPECT_FALSE(IsPrime(4));EXPECT_TRUE(IsPrime(5));EXPECT_FALSE(IsPrime(6));EXPECT_TRUE(IsPrime(23)); } } // namespace View Codeg++ sample.c sample_unittest.c? -lgtest -std=c++11 -lgtest_main -lpthread -o test
沒有main函數
使用Gtest你可以不提供main函數,libgtest_main.a會為你提供一個。如果沒有特殊理由還是建議自己提供main函數
main.c
#include <gtest/gtest.h> int main(int argc, char** argv){::testing::InitGoogleTest(&argc, argv);return RUN_ALL_TESTS(); } View Codeg++ sample.c sample_unittest.c? main.c -lgtest -std=c++11 -lpthread -o test
::testing::InitGoogleTest?方法的作用就是對框架進行初始化,必須在調用?RUN_ALL_TESTS?之前調用它。在代碼中只能調用?RUN_ALL_TESTS?一次,因為多次調用會與框架的一些高級特性沖突,不支持這種做法。注意,RUN_ALL_TESTS自動地探測并運行用?TEST?宏定義的所有測試。在默認情況下,結果輸出到標準輸出。
編譯、運行結果和上面一樣。
Gtest選項
InitGoogleTest?函數接收傳遞給test infrastructure的參數,下面介紹常用參數
通過在命令行上傳遞?--gtest_output="xml:report.xml",可以把輸出轉儲為 XML 格式。當然,可以把?report.xml?替換為您喜歡的任何文件名。
某些測試有時候會失敗,但是在大多數時候會順利通過。這是與memory corruption相關的問題的典型特點。如果多次運行測試,就能夠提高發現失敗的可能性。如果在命令行上傳遞?--gtest_repeat=2 --gtest_break_on_failure,就重復運行相同的測試兩次。如果測試失敗,會自動調用調試器。
并不需要每次都運行所有測試,尤其是在修改的代碼只影響某幾個模塊的情況下。為了支持運行一部分測試,Google 提供?--gtest_filter=<test string>。test string 的格式是由冒號 (:) 分隔的一系列通配符模式。例如,--gtest_filter=*?運行所有測試,而?--gtest_filter=SquareRoot*?只運行?SquareRootTest?測試。如果希望只運行?SquareRootTest?中的正數單元測試,應該使用?--gtest_filter=SquareRootTest.*-SquareRootTest.Zero*。注意,SquareRootTest.*?表示屬于?SquareRootTest?的所有測試,而?-SquareRootTest.Zero*?表示不運行名稱以 Zero 開頭的測試。
禁用臨時測試
可以臨時禁用測試嗎?可以,只需在邏輯測試名或單元測試名前面加上?DISABLE_?前綴,它就不會執行了。
禁用臨時測試
#include "gtest/gtest.h"TEST (DISABLE_SquareRootTest, PositiveNos) { EXPECT_EQ (18.0, square-root (324.0));EXPECT_EQ (25.4, square-root (645.16));EXPECT_EQ (50.3321, square-root (2533.310224)); }ORTEST (SquareRootTest, DISABLE_PositiveNos) { EXPECT_EQ (18.0, square-root (324.0));EXPECT_EQ (25.4, square-root (645.16));EXPECT_EQ (50.3321, square-root (2533.310224)); } View Code注意,如果禁用了任何測試,Google 框架會在測試執行結束時輸出警告消息,Google 警告用戶在框架中有禁用的測試
1 FAILED TESTYOU HAVE 1 DISABLED TEST View Code如果希望繼續運行禁用的測試,那么在命令行上傳遞?-gtest_also_run_disabled_tests?選項。
Assertions(斷言)
演示用于浮點數比較的宏
ASSERT_FLOAT_EQ (expected, actual) ASSERT_DOUBLE_EQ (expected, actual) ASSERT_NEAR (expected, actual, absolute_range)EXPECT_FLOAT_EQ (expected, actual) EXPECT_DOUBLE_EQ (expected, actual) EXPECT_NEAR (expected, actual, absolute_range) View Code為什么需要用單獨的宏進行浮點數比較?使用?ASSERT_EQ?不行嗎?使用?ASSERT_EQ?和相關的宏可能可以,也可能不行,但是使用專門用于浮點數比較的宏更好。通常,不同的中央處理單元 (CPU) 和操作環境以不同的方式存儲浮點數,簡單地比較期望值和實際值是無效的。例如,ASSERT_FLOAT_EQ (2.00001, 2.000011)?會順利通過 — 如果直到小數點后四位都匹配,Google 就不會拋出錯誤。如果需要更精確的比較,應該使用?ASSERT_NEAR (2.00001, 2.000011, 0.0000001),就會得到 下面所示的錯誤。
Math.cc(68): error: The difference between 2.00001 and 2.000011 is 1e-006, which exceeds 0.0000001, where 2.00001 evaluates to 2.00001, 2.000011 evaluates to 2.00001, and 0.0000001 evaluates to 1e-007. View Code斷言引發的三種結果
Assertions會引發3種結果:success、Non-Fatal Failure、Fatal Failure
Non-Fatal Failure 和?Fatal Failure啥區別?
前者失敗后還會繼續執行,后者失敗后停止執行。ASSERT_XX屬于fatal assertion,EXPECT_XX屬于nonfatal assertion。
不建議才一個測試單元里面寫多個assertion
當有多個Non-Fatal Assertion時,不管有多少個assertion通過,只要有一個不通過,該測試用例就不通過。
如果把第一個EXPECT_EQ換成ASSERT_EQ,那么斷言失敗時停止執行,后面代碼不會被執行。雖然你可以通過日志去翻那個文件、哪個函數、哪段代碼第幾行執行錯誤。這種情況適合于測試用例少的情況,上百個測試用例的時候,這種排查發簡直是噩夢。一個建議原則是one region one assertion
理解test fixtures
在執行單元測試之前,通常要執行一些定制的初始化。例如,如果希望度量測試的時間/內存占用量,就需要放置一些測試專用代碼以度量這些值。這就是fixtures的用途 — 它們幫助完成這種定制的測試初始化。代碼如下
A test fixture class
class myTestFixture1: public ::testing::test { public: myTestFixture1( ) { // initialization code here } void SetUp( ) { // code here will execute just before the test ensues }void TearDown( ) { // code here will be called just after the test completes// ok to through exceptions from here if need be }~myTestFixture1( ) { // cleanup any pending stuff, but no exceptions allowed }// put in any custom data members that you need }; View Code這個fixtures class派生自?gtest.h?中聲明的?::testing::test?類。下面是使用這個裝備類的示例。注意,它使用?TEST_F?宏而不是?TEST。
TEST_F (myTestFixture1, UnitTest1) { . }TEST_F (myTestFixture1, UnitTest2) { . } View Code在使用裝備時,要注意以下幾點:
- 可以在構造函數或?SetUp?方法中執行初始化或分配資源。由用戶選擇具體方式。
- 可以在?TearDown?或析構函數例程中釋放資源。但是,如果需要異常處理,那么只能在?TearDown?代碼中進行,因為從析構函數中拋出異常會導致不確定的結果。
- 在以后的版本中,Google 斷言宏可能會在平臺上拋出異常。因此,為了便于維護,最好在?TearDown?代碼中使用斷言宏(assertion macros)。
- 不存在多個測試使用同一個test fixture。對于每個新的測試單元,框架創建一個新的test fixture。在上面代碼中,由于要創建兩個?myFixture1?對象,所以兩次調用?SetUp?例程(請注意使用正確的拼寫)。
轉載于:https://www.cnblogs.com/kelamoyujuzhen/p/10161362.html
總結
以上是生活随笔為你收集整理的A quick introduction to Google test的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 探析“Java序列化”之serialVe
- 下一篇: 腾讯云Service Mesh生产实践及