程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> C語言 >> C++ >> C++入門知識 >> Google C++單元測試框架GoogleTest---AdvancedGuide(譯文)下,advancediqtest

Google C++單元測試框架GoogleTest---AdvancedGuide(譯文)下,advancediqtest

編輯:C++入門知識

Google C++單元測試框架GoogleTest---AdvancedGuide(譯文)下,advancediqtest


因為AdvancedGuide文檔太長,分上下兩部分,本文檔接googletest--AdvancedGuide(譯文)上:Google C++單元測試框架GoogleTest---AdvancedGuide(譯文)上。

一、在子程序中使用斷言(Using Assertions in Sub-routines)

1.1 將跟蹤添加到斷言

如果從幾個地方調用測試子程序,當其中的斷言失敗時,可能很難判斷失敗來自哪個子程序的調用。 您可以使用額外的日志或自定義失敗消息緩解這個問題,但通常會堵塞您的測試。 更好的解決方案是使用SCOPED_TRACE宏:

SCOPED_TRACE(message);

messsage可以是任何可以流入std::ostream的東西。此宏會將當前文件名、行號和給定消息添加到每個失敗消息中。 當控件離開當前詞法作用域時,效果將被撤消。

For example,

 void Sub1(int n) {
   EXPECT_EQ(1, Bar(n));
   EXPECT_EQ(2, Bar(n + 1));
 }

 TEST(FooTest, Bar) {
   {
     SCOPED_TRACE("A");  // This trace point will be included in
                         // every failure in this scope.
     Sub1(1);
   }//到這SCOPED_TRACE的作用域就結束。
   // Now it won't.
   Sub1(9);//都調用了子程序Sub1
 }

可能會導致這樣的消息:

path/to/foo_test.cc:11: Failure
Value of: Bar(n)
Expected: 1
  Actual: 2
   Trace:
path/to/foo_test.cc:17: A

path/to/foo_test.cc:12: Failure
Value of: Bar(n + 1)
Expected: 2
  Actual: 3

沒有跟蹤,很難知道兩個失敗分別來自哪個Sub1()的調用。 (你可以在Sub1()中為每個斷言添加一個額外的消息,以指示n的值,但這很乏味。)

關於使用SCOPED_TRACE的一些提示:

沒有跟蹤,很難知道兩個失敗分別來自哪個Sub1()的調用。 (你可以在Sub1()中為每個斷言添加一個額外的消息,以指示n的值,但這很乏味。)

關於使用SCOPED_TRACE的一些提示:

  • 使用合適的消息,通常足以在子例程的開頭使用SCOPED_TRACE,而不是在每個調用站點。
  • 當調用循環內的子例程時,使循環迭代器成為SCOPED_TRACE中的消息的一部分,以便您可以知道失敗來自哪個迭代。
  • 有時,跟蹤點的行號足以識別子例程的特定調用。在這種情況下,您不必為SCOPED_TRACE選擇唯一的消息。你可以簡單地使用“”。
  • 當外部作用域中有一個SCOPED_TRACE時,可以在內部作用域中使用SCOPED_TRACE。在這種情況下,所有活動跟蹤點將按照遇到的相反順序包含在失敗消息中。
  • 跟蹤轉儲是可以在Emacs的編譯緩沖區中點擊 - 命中返回行號,你會被帶到源文件中的那一行!

1.2 傳播致命失敗

使用ASSERT_ *和FAIL *時的常見陷阱認為當它們失敗時,它們會中止整個測試。 例如,以下測試將會導致錯誤:

void Subroutine() {
  // Generates a fatal failure and aborts the current function.
  ASSERT_EQ(1, 2);//失敗時只是終止當前函數
  // The following won't be executed.
  ...
}

TEST(FooTest, Bar) {
  Subroutine();
  // The intended behavior is for the fatal failure
  // in Subroutine() to abort the entire test.
  // The actual behavior: the function goes on after Subroutine() returns.
  //  實際行為:函數在Subroutine()返回後繼續。
  int* p = NULL;
  *p = 3; // Segfault!產生一個錯誤
} 

由於我們不使用異常,因此在技術上不可能在這裡實現預期的行為。 為了減輕這種情況,Google測試提供了兩種解決方案。 您可以使用(ASSERT | EXPECT)_NO_FATAL_FAILURE斷言或HasFatalFailure()函數。 它們在以下兩個小節中描述。

1.3在子程序中的斷言(Asserting on Subroutines)

如上所示,如果你的測試調用了一個有ASSERT_ *失敗的子程序,測試將在子程序返回後繼續。 這可能不是你想要的。

通常人們希望致命的失敗傳播像異常一樣。 為此,Google測試提供以下宏:

Fatal assertionNonfatal assertionVerifies ASSERT_NO_FATAL_FAILURE(statement); EXPECT_NO_FATAL_FAILURE(statement); statement doesn't generate any new fatal failures in the current thread.

僅檢查執行斷言的線程中的失敗,以確定這種類型的斷言的結果。 如果語句創建新線程,這些線程中的失敗將被忽略。

例如:

ASSERT_NO_FATAL_FAILURE(Foo());

int i;
EXPECT_NO_FATAL_FAILURE({
  i = Bar();
}); 

1.4檢查當前測試中的故障

  :: test :: Test類中的HasFatalFailure(): 如果當前測試中的斷言遭遇致命故障,則返回true。 這允許函數捕獲子例程中的致命故障並及早返回。

class Test {
 public:
  ...
  static bool HasFatalFailure();
};

 典型的用法,基本上模擬拋出的異常的行為是:

TEST(FooTest, Bar) {  
    Subroutine();  // Aborts if Subroutine() had a fatal failure. 
   if (HasFatalFailure())    
     return;  
   // The following won't be executed. 
   ...
}

HasFatalFailure如果在TEST(),TEST_F()或測試夾具之外使用,則必須添加:: testing :: Test ::前綴,如: 

if (::testing::Test::HasFatalFailure())
  return;

類似的,HasNonfatalFailure():如果當前測試至少有一個非致命失敗,返回true。

HasFailure() :如果當前測試至少有一個失敗,返回true。

二、記錄其他信息Logging Additional Information

在測試代碼中,可以調用RecordProperty(“key”,value)來記錄附加信息,其中value可以是字符串或int。 如果指定一個鍵,則為鍵記錄的最後一個值將發送到XML輸出。

例如

TEST_F(WidgetUsageTest, MinAndMaxWidgets) {
  RecordProperty("MaximumWidgets", ComputeMaxUsage());
  RecordProperty("MinimumWidgets", ComputeMinUsage());
}

will output XML like this:

...
  <testcase name="MinAndMaxWidgets" status="run" time="6" classname="WidgetUsageTest"
            MaximumWidgets="12"
            MinimumWidgets="9" />
...

注意:

  • RecordProperty()是Test類的靜態成員。 因此,如果在TEST體和測試夾具類之外使用,則需要使用前綴:: testing :: Test ::
  • 鍵必須是有效的XML屬性名稱,且不能與Google Test(名稱,狀態,時間,類名,類型_參數和值_參數)已使用的鍵沖突。
  • 允許在測試的生命周期之外調用RecordProperty()。 如果它在測試之外調用,但在測試用例的SetUpTestCase()和TearDownTestCase()方法之間調用,它將被歸因於測試用例的XML元素。 如果在所有測試用例之外調用(例如在測試環境中),它將被歸因於頂級XML元素。

三、在同一測試用例中的測試之間共享資源

Google Test為每個測試創建一個新的測試夾具對象,以使測試獨立,更容易調試。 然而,有時測試使用昂貴的資源設置,使得單拷貝測試模型過於昂貴。

如果測試不更改資源,則它們在共享單個資源副本中沒有任何危害。 因此,除了每次測試的set-up/tear-down,Google測試還支持每個測試用例的set-up/tear-down。 使用它:

  • 在你的測試夾具類(比如FooTest)中,定義一些成員變量來保存共享資源。
  • 在同一個測試夾具類中,定義一個靜態void SetUpTestCase()函數(記住不要拼寫它作為一個小u的SetupTestCase)來設置共享資源和靜態void TearDownTestCase()函數來刪除它們。

OK! 在運行FooTest測試用例中的第一個測試(即在創建第一個FooTest對象之前)之前,Google Test自動調用SetUpTestCase(),並在運行最後一個測試之後(即刪除最後一個FooTest對象後)調用TearDownTestCase()。 在其間,測試可以使用共享資源。

記住測試順序是未定義的,所以你的代碼不能依賴於另一個之前或之後的測試。 此外,測試必須不能修改任何共享資源的狀態,或者,如果它們修改狀態,則它們必須在將控制傳遞給下一個測試之前將狀態恢復到其原始值。

Here's an example of per-test-case set-up and tear-down:

class FooTest : public ::testing::Test {
 protected:
  // Per-test-case set-up.
  // Called before the first test in this test case.
  // Can be omitted if not needed.
  static void SetUpTestCase() {
    shared_resource_ = new ...;
  }

  // Per-test-case tear-down.
  // Called after the last test in this test case.
  // Can be omitted if not needed.
  static void TearDownTestCase() {
    delete shared_resource_;
    shared_resource_ = NULL;
  }

  // You can define per-test set-up and tear-down logic as usual.
  virtual void SetUp() { ... }
  virtual void TearDown() { ... }

  // Some expensive resource shared by all tests.
  static T* shared_resource_;
};

T* FooTest::shared_resource_ = NULL;

TEST_F(FooTest, Test1) {
  ... you can refer to shared_resource here ...
}
TEST_F(FooTest, Test2) {
  ... you can refer to shared_resource here ...
}

四、Global Set-Up and Tear-Down

正如你可以在測試級別和測試用例級別設置和拆卸,您也可以在測試程序級別執行。

首先,你要繼承:: testing :: Environment類來定義一個測試環境:

class Environment {
 public:
  virtual ~Environment() {}
  // Override this to define how to set up the environment.
  virtual void SetUp() {}
  // Override this to define how to tear down the environment.
  virtual void TearDown() {}
};

然後,通過調用:: testing :: Add Global Test Environment()函數,注冊我們的環境類的實例:

Environment* AddGlobalTestEnvironment(Environment* env);

現在,當調用RUN_ALL_TESTS()時,它首先調用環境對象的SetUp()方法,然後如果沒有致命失敗則運行測試,最後調用環境對象的TearDown()。

注冊多個環境對象是可以的。 在這種情況下,他們的SetUp()將按照它們注冊的順序被調用,並且它們的TearDown()將以相反的順序被調用。

請注意,Google測試會對注冊的環境對象擁有所有權。 因此,不要自己刪除它們。

您應該在調用RUN_ALL_TESTS()之前調用AddGlobalTestEnvironment(),可能在main()中調用。 如果你使用gtest_main,你需要在main()啟動之前調用它才能生效。 一種方法是定義一個全局變量,如下所示:

::testing::Environment* const foo_env = ::testing::AddGlobalTestEnvironment(new FooEnvironment); 

但是,我們強烈建議您編寫自己的main()並調用AddGlobalTestEnvironment(),因為依賴於全局變量的初始化使代碼更難讀取,並且可能會導致問題,當您從不同的轉換單元注冊多個環境, 它們之間的依賴性(記住編譯器不保證來自不同轉換單元的全局變量的初始化順序)。

 五、值參數化測試

//這個功能挺復雜,專門寫在一個單獨的文檔解析:

 http://www.cnblogs.com/jycboy/p/6118073.html

 六、類型測試

假設您有一個接口的多個實現,並希望確保所有這些都滿足一些常見的要求。 或者,您可能定義了幾個類型,它們應該符合相同的“概念”,並且您想要驗證它。 在這兩種情況下,您都希望為不同類型重復相同的測試邏輯。 

 雖然你可以為你想測試的每個類型寫一個TEST或TEST_F(你甚至可以把測試邏輯放入你從TEST調用的函數模板),它是乏味的,不縮放:如果你想要m個測試 n類型,你最終會寫m * n TESTs。

類型測試允許您在類型列表上重復相同的測試邏輯。 你只需要寫一次測試邏輯,雖然在寫類型測試時你必須知道類型列表。 以下是您的操作方法:

1. 定義一個fixture類模板。 它應該由一個類型參數化。 記住繼承:: testing :: Test:

template <typename T>
class FooTest : public ::testing::Test {
 public:
  ...
  typedef std::list<T> List;
  static T shared_;
  T value_;
};

2. 將類型列表與測試用例相關聯,這將針對列表中的每個類型重復:

typedef ::testing::Types<char, int, unsigned int> MyTypes;
TYPED_TEST_CASE(FooTest, MyTypes);

typedef對於TYPED_TEST_CASE宏正確解析是必要的。 否則編譯器會認為類型列表中的每個逗號引入一個新的宏參數。

3. 使用TYPED_TEST()而不是TEST_F()為此測試用例定義一個類型測試。 您可以根據需要重復此操作次數:

TYPED_TEST(FooTest, DoesBlah) {
  // Inside a test, refer to the special name TypeParam to get the type
  // parameter.  Since we are inside a derived class template, C++ requires
  // us to visit the members of FooTest via 'this'.
  TypeParam n = this->value_;

  // To visit static members of the fixture, add the 'TestFixture::'
  // prefix.
  n += TestFixture::shared_;

  // To refer to typedefs in the fixture, add the 'typename TestFixture::'
  // prefix.  The 'typename' is required to satisfy the compiler.
  typename TestFixture::List values;
  values.push_back(n);
  ...
}

TYPED_TEST(FooTest, HasPropertyA) { ... }

You can see samples/sample6_unittest.cc for a complete example.

七、類型參數化測試

在不知道類型參數的情況下編寫測試--- 這就是“類型參數化測試”。

類型參數化測試類似於類型測試,除了它們不需要預知類型列表。 相反,您可以首先定義測試邏輯,然後使用不同類型列表實例化它。 你甚至可以在同一個程序中多次實例化它。

如果您正在設計一個接口或概念,則可以定義一組類型參數化測試,以驗證接口/概念的任何有效實現應具有的屬性。 然後,每個實現的作者可以使用他的類型來實例化測試套件,以驗證它符合需求,而不必重復地編寫類似的測試。 這裡有一個例子:

1. 定義一個fixture類模板,就像我們用類型測試一樣:

First, define a fixture class template, as we did with typed tests:

template <typename T>
class FooTest : public ::testing::Test {
  ...
};

2. 聲明你要定義的類型參數化測試用例:

TYPED_TEST_CASE_P(FooTest);

這個後綴P代表參數化或模式,隨你怎麼想。

3. 使用TYPED_TEST_P()來定義類型參數化測試。您可以根據需要重復多次:

TYPED_TEST_P(FooTest, DoesBlah) {
  // Inside a test, refer to TypeParam to get the type parameter.
  TypeParam n = 0;
  ...
}

TYPED_TEST_P(FooTest, HasPropertyA) { ... }

現在棘手的部分:您需要使用REGISTER_TYPED_TEST_CASE_P宏注冊所有測試模式,然後才能實例化它們。

宏的第一個參數是測試用例名稱; 其余的是在這個測試用例中的測試的名稱

REGISTER_TYPED_TEST_CASE_P(FooTest,
                           DoesBlah, HasPropertyA);

最後,你可以用你想要的類型來實例化模式。 如果你把上面的代碼放在頭文件中,你可以在多個C ++源文件#include它,並實例化多次。

typedef ::testing::Types<char, int, unsigned int> MyTypes;
INSTANTIATE_TYPED_TEST_CASE_P(My, FooTest, MyTypes);

為了區分模式的不同實例,INSTANTIATE_TYPED_TEST_CASE_P宏的第一個參數是將添加到實際測試用例名稱中的前綴。 請記住為不同實例選擇唯一前綴

在類型列表只包含一個類型的特殊情況下,您可以直接編寫該類型,而不使用:: testing :: Types <...>,如下所示:

INSTANTIATE_TYPED_TEST_CASE_P(My, FooTest, int);

ou can see samples/sample6_unittest.cc for a complete example.

**類型測試與類型參數化的區別:

1. 類型測試是你知道所有的類型,把所有類型注冊,實例化測試。

2. 類型參數化是你是接口的定義者,知道每個接口函數的基本功能,而它的具體實現可以在將來被   人實現,你可以提前定義好測試用例,然後把所有的測試注冊。

八、測試private修飾的代碼

如果您更改軟件的內部實現,只要用戶不能觀察到這種變化,您的測試就不會中斷。 因此,根據黑盒測試原則,大多數時候你應該通過其公共接口測試你的代碼。

如果你仍然發現自己需要測試內部實現代碼,考慮是否有一個更好的設計,不需要你這樣做。 如果你必須測試非公共接口代碼。 有兩種情況需要考慮:

  •  靜態函數(不同於靜態成員函數!)或未命名的命名空間
  •  私人或受保護的類成員

 1. 靜態函數

未命名的命名空間中的靜態函數和定義/聲明僅在同一轉變單元中可見。要測試它們,您可以在你的* _test.cc文件中include 要測試的整個.cc文件。 (#include .cc文件不是重用代碼的好方法 - 你不應該在生產代碼中這樣做!)

然而,更好的方法是將私有代碼移動到foo :: internal命名空間中,其中foo是你項目通常使用的命名空間,並將私有聲明放在* -internal.h文件中。允許您的生產.cc文件和測試包括此內部標頭,但是您的客戶端不包括。這樣,您可以完全測試您的內部實現,而不會洩漏到您的客戶端。

2. 私有類成員

私人class成員只能從班class或友元類那裡接觸。要訪問類的私有成員,可以將測試夾具聲明為類的朋友,並在夾具中定義訪問器。使用夾具的測試,可以通過夾具中的訪問器訪問您的生產類的私有成員。注意,即使你的夾具是你的生產類的朋友,你的測試不是它的友元類,因為他們技術上是定義在夾具的子類中。

另一種測試私有成員的方法是將它們重構為一個實現類,然後在* -internal.h文件中聲明它。您的客戶端不允許包括此標題,但您的測試可以。這種稱為Pimpl(私有實現)習語。

或者,您可以通過在類主體中添加以下行,將個別測試聲明為class的友元類:

FRIEND_TEST(TestCaseName, TestName);

  For example,

// foo.h
#include "gtest/gtest_prod.h"

// Defines FRIEND_TEST.
class Foo {
  ...
 private:
  FRIEND_TEST(FooTest, BarReturnsZeroOnNull);
  int Bar(void* x);
};

// foo_test.cc
...
TEST(FooTest, BarReturnsZeroOnNull) {
  Foo foo;
  EXPECT_EQ(0, foo.Bar(NULL));
  // Uses Foo's private member Bar().
}

當你的類在命名空間中定義時,需要特別注意,因為你應該在同一個命名空間中定義你的測試夾具和測試,如果你想他們是你的class的友元。 例如,如果要測試的代碼如下所示:

namespace my_namespace {

class Foo {
  friend class FooTest;
  FRIEND_TEST(FooTest, Bar);
  FRIEND_TEST(FooTest, Baz);
  ...
  definition of the class Foo
  ...
};

}  // namespace my_namespace

Your test code should be something like:

namespace my_namespace {
class FooTest : public ::testing::Test {
 protected:
  ...
};

TEST_F(FooTest, Bar) { ... }
TEST_F(FooTest, Baz) { ... }

}  // namespace my_namespace

九、Catching Failures

如果您要在Google測試之上構建測試實用程序,則需要測試您的實用程序。 你將使用什麼框架來測試它? Google測試,當然。

挑戰是驗證您的測試實用程序是否正確報告故障。 在框架中通過拋出異常報告失敗,您可以捕獲異常並斷言。 但是Google Test不會使用異常,那麼我們如何測試一段代碼是否會產生預期的失敗呢?

“gtest / gtest-spi.h”包含一些構造來做到這一點。 #include 它,然後可以使用

EXPECT_FATAL_FAILURE(statement, substring);​

to assert that statement generates a fatal (e.g. ASSERT_*) failure whose message contains the given substring, or use

EXPECT_NONFATAL_FAILURE(statement, substring);​

if you are expecting a non-fatal (e.g. EXPECT_*) failure.

。。。。。//需要時再看

十、Getting the Current Test's Name

   有時一個函數可能需要知道當前運行的測試的名稱。 例如,您可以使用測試夾具的SetUp()方法根據正在運行的測試設置黃金文件名。 :: testing :: TestInfo類具有以下信息:

namespace testing {

class TestInfo {
 public:
  // Returns the test case name and the test name, respectively.
  //
  // Do NOT delete or free the return value - it's managed by the
  // TestInfo class.
  const char* test_case_name() const;
  const char* name() const;
};

}  // namespace testing

To obtain a TestInfo object for the currently running test, call current_test_info() on the UnitTest singleton object:

// Gets information about the currently running test.
// Do NOT delete the returned object - it's managed by the UnitTest class.
const ::testing::TestInfo* const test_info =
  ::testing::UnitTest::GetInstance()->current_test_info();
printf("We are in test %s of test case %s.\n",
       test_info->name(), test_info->test_case_name());

如果沒有運行測試,current_test_info()返回一個空指針。 特別是,你不能在TestCaseSetUp(),TestCaseTearDown()中找到測試用例名稱(在那裡你知道測試用例名稱),或者從它們調用的函數。

十 一、運行測試程序:高級選項

Google Test測試程序是普通的可執行文件。 一旦構建,您可以直接運行它們,並通過以下環境變量 命令行標志影響其行為。 要使標志工作,您的程序必須在調用RUN_ALL_TESTS()之前調用:: testing :: InitGoogleTest()。

要查看支持的標志及其用法的列表,請使用--help標志運行測試程序。 您也可以使用-h, - ?或/? 簡稱。 此功能在版本1.3.0中添加。
設置標志的三種方式:以--gtest_filter 為例        1)命令行運行程序時直接加上參數:./foo_test --gtest_filter=QueueTest.*;       2)在代碼中設置::: testing :: GTEST_FLAG(filter)= "QueueTest.*" **注意沒有前邊的--gtest_。       3)testing::FLAGS_gtest_filter = "QueueTest.*"; 如果選項由環境變量和標志指定,則後者優先。 大多數選項也可以在代碼中設置/讀取:訪問命令行標志的值--gtest_foo,write :: testing :: GTEST_FLAG(foo)。  **注意標志是:--gtest_foo ; 在代碼中調用是:: testing :: GTEST_FLAG(foo);沒有前邊的--gtest_。 一個常見的模式是在調用:: testing :: InitGoogleTest()之前設置標志的值:
int main(int argc, char** argv) {
  // Disables elapsed time by default.
  ::testing::GTEST_FLAG(print_time) = false;

  // This allows the user to override the flag on the command line.
  ::testing::InitGoogleTest(&argc, argv);

  return RUN_ALL_TESTS();
}  

1. 選擇測試

   此部分顯示用於選擇哪些測試運行的各種選項。

 1.1 列出測試名稱
  有時,在運行程序之前,必須列出程序中的可用測試,以便在需要時應用過濾器。 包括標志--gtest_list_tests覆蓋所有其他標志,並列出以下格式的測試:
TestCase1.
  TestName1
  TestName2
TestCase2.
  TestName

如果提供了標志,則列出的所有測試都不會真正運行。 此標志沒有相應的環境變量。

  1.2運行測試的子集

默認情況下,Google測試程序運行用戶定義的所有測試。 有時,您只想運行測試的一個子集(例如,用於調試或快速驗證更改)。 如果將GTEST_FILTER環境變量或--gtest_filter標志設置為過濾器字符串,則Google Test將僅運行其全名(以TestCaseName.TestName的形式)與過濾器匹配的測試。

過濾器的格式是通配符模式(稱為正模式)的':'分隔的列表,可選地後跟一個“ - ”和另一個“:”分隔的模式列表(稱為負模式)。 測試匹配過濾器當且僅當它與任何正模式匹配但不匹配任何負模式時。

模式可能包含“*”(匹配任何字符串)或'?' (匹配任何單個字符)。 為了方便,過濾器'* -NegativePatterns'也可以寫為'-NegativePatterns'。

For example:

  • ./foo_test Has no flag, and thus runs all its tests.
  • ./foo_test --gtest_filter=* Also runs everything, due to the single match-everything * value.
  • ./foo_test --gtest_filter=FooTest.* Runs everything in test case FooTest.
  • ./foo_test --gtest_filter=*Null*:*Constructor* Runs any test whose full name contains either "Null" or "Constructor".
  • ./foo_test --gtest_filter=-*DeathTest.* Runs all non-death tests.
  • ./foo_test --gtest_filter=FooTest.*-FooTest.Bar Runs everything in test case FooTest except FooTest.Bar.

 1.3 暫時禁用測試

如果你有一個失敗的測試,無法立即修復,可以在其名稱中添加DISABLED_前綴。 將排除它執行。 這比注釋掉代碼或使用#if 0更好,因為禁用的測試仍然編譯(因此不會rot)。

如果你需要禁用測試用例中的所有測試,可以在每個測試名稱的前面添加DISABLED_,或者將其添加到測試用例名稱的前面。

例如,以下測試不會由Google Test運行,即使它們仍然將被編譯:

// Tests that Foo does Abc.
TEST(FooTest, DISABLED_DoesAbc) { ... }

class DISABLED_BarTest : public ::testing::Test { ... };

// Tests that Bar does Xyz.
TEST_F(DISABLED_BarTest, DoesXyz) { ... } 

注意:此功能只能用於臨時緩解。 您仍然必須在以後修復已禁用的測試。 提醒您,如果測試計劃包含任何已停用的測試,Google測試會打印一條橫幅警告您。

提示:您可以輕松計算已使用grep禁用的測試的數量。 此數字可用作提高測試質量的指標。

1.4 暫時啟用禁用測試

要在測試執行中包括禁用的測試,只需使用--gtest_also_run_disabled_tests標志調用測試程序或將GTEST_ALSO_RUN_DISABLED_TESTS環境變量設置為0以外的值。您可以將此與--gtest_filter標志結合,以進一步選擇要運行哪些已禁用的測試 。

代碼中設置如下:前邊加FLAGS_ (好坑啊,文檔裡也沒說,我查出來的)。

testing::FLAGS_gtest_also_run_disabled_tests = 2;

2. 重復測試

有一段時間,你會碰到一個測試,它的結果是命中或錯過。 也許它只會失敗1%的時間,使它很難重現調試器下的錯誤。 這可能是挫折的主要根源。

--gtest_repeat標志允許您在程序中重復所有(或選定的)測試方法多次。 希望,一個脆弱的測試最終會失敗,並給你一個機會進行調試。 以下是使用方法:

$ foo_test --gtest_repeat=1000Repeat foo_test 1000 times and don't stop at failures. $ foo_test --gtest_repeat=-1 A negative count means repeating forever. $ foo_test --gtest_repeat=1000 --gtest_break_on_failure Repeat foo_test 1000 times, stopping at the first failure. This is especially useful when running under a debugger: when the testfails, it will drop into the debugger and you can then inspect variables and stacks. $ foo_test --gtest_repeat=1000 --gtest_filter=FooBar Repeat the tests whose name matches the filter 1000 times.

 如果您的測試程序包含使用AddGlobalTestEnvironment()注冊的全局set-up/tear-down代碼,則在每次迭代中都會重復該測試程序,因為其中可能存在薄片。 您還可以通過設置GTEST_REPEAT環境變量來指定重復計數。

 3.Shuffling the Tests洗牌測試

您可以指定--gtest_shuffle標志(或將GTEST_SHUFFLE環境變量設置為1),以便以隨機順序在程序中運行測試。 這有助於揭示測試之間的依賴關系。

默認情況下,Google測試使用根據當前時間計算的隨機種子。 因此,你每次都會得到不同的順序。 控制台輸出包括隨機種子值,以便以後可以重現與順序相關的測試失敗。 要明確指定隨機種子,請使用--gtest_random_seed = SEED標志(或設置GTEST_RANDOM_SEED環境變量),其中SEED是介於0和99999之間的整數。種子值0是特殊的:它告訴Google Test執行默認行為 從當前時間計算種子。

如果將此與--gtest_repeat = N結合使用,Google測試會選擇不同的隨機種子,並在每次迭代中重新洗牌測試。

 4.控制測試輸出

 本節教導如何調整測試結果的報告方式。

  4.1彩色終端輸出

Google測試可以在其終端輸出中使用顏色,以便更容易地發現測試之間的分離,以及測試是否通過。

您可以設置GTEST_COLOR環境變量,或將--gtest_color命令行標志設置為yes,no或auto(默認值)以啟用顏色,禁用顏色或讓Google測試決定。 當值為auto時,如果且僅當輸出發送到終端,並且(在非Windows平台上)TERM環境變量設置為xterm或xterm-color,Google Test將使用顏色。

 4.2 抑制所用時間

默認情況下,Google測試會打印運行每個測試所需的時間。為了抑制這種情況,使用--gtest_print_time = 0命令行標志運行測試程序。將GTEST_PRINT_TIME環境變量設置為0具有相同的效果。

可用性:Linux,Windows,Mac。 (在Google Test 1.3.0及更低版本中,默認行為是不打印已用時間。)

 4.3 生成XML報告

  除了正常的文本輸出之外,Google Test還可以向文件發送詳細的XML報告。報告包含每個測試的持續時間,因此可以幫助您識別慢速測試。

要生成XML報告,請將GTEST_OUTPUT環境變量或--gtest_output標志設置為字符串“xml:_path_to_output_file_”,這將在給定位置創建文件。您也可以只使用字符串“xml”,在這種情況下,輸出可以在當前目錄中的test_detail.xml文件中找到。

  如果指定目錄(例如,Linux上的“xml:output / directory /”或Windows上的“xml:output \ directory \”),Google Test將在該目錄中創建一個XML文件(測試程序foo_test或foo_test.exe的foo_test.xml)。如果文件已存在(可能是上次運行時遺留的文件),Google測試會選擇不同的名稱(例如foo_test_1.xml),以避免覆蓋它。

報告使用此處描述的格式。它基於junitreport Ant任務,可以通過流行的連續構建系統(如Hudson)進行解析。由於該格式最初是用於Java,需要稍作解釋才能將其應用於Google Test測試,如下所示:

<testsuites name="AllTests" ...>
  <testsuite name="test_case_name" ...>
    <testcase name="test_name" ...>
      <failure message="..."/>
      <failure message="..."/>
      <failure message="..."/>
    </testcase>
  </testsuite>
</testsuites>
  • <testsuites>根元素對應於整個測試程序。
  • <testsuite> 元素對應與test case.
  • <testcase> 元素對應於Google Test測試函數。

For instance, the following program

TEST(MathTest, Addition) { ... }
TEST(MathTest, Subtraction) { ... }
TEST(LogicTest, NonContradiction) { ... }

could generate this report:

<?xml version="1.0" encoding="UTF-8"?>
<testsuites tests="3" failures="1" errors="0" time="35" name="AllTests">
  <testsuite name="MathTest" tests="2" failures="1" errors="0" time="15">
    <testcase name="Addition" status="run" time="7" classname="">
      <failure message="Value of: add(1, 1)
 Actual: 3
Expected: 2" type=""/>
      <failure message="Value of: add(1, -1)
 Actual: 1
Expected: 0" type=""/>
    </testcase>
    <testcase name="Subtraction" status="run" time="5" classname="">
    </testcase>
  </testsuite>
  <testsuite name="LogicTest" tests="1" failures="0" errors="0" time="5">
    <testcase name="NonContradiction" status="run" time="5" classname="">
    </testcase>
  </testsuite>
</testsuites>

注意事項:

  •  <testuites>元素的tests屬性包含多少個測試,而failures屬性告訴它們有多少個失敗。
     <testcase>元素的屬性:該測試用例中包含多少個測試;
  •  time屬性以毫秒表示測試、測試用例或整個測試程序的持續時間。
  •  每個<failure>元素對應於單個失敗的Google Test斷言。
  • 某些JUnit概念不適用於Google測試,但我們必須符合DTD。 因此,您將在報告中看到一些虛擬元素和屬性。 您可以安全地忽略這些部分。

5.控制如何報告失敗

 5.1 將斷言失敗轉換為斷點

  當在調試器下運行測試程序時,如果調試器可以捕獲斷言故障並自動進入交互模式,則非常方便。 Google測試的break-on-failure 模式支持此行為。

  要啟用它,請將GTEST_BREAK_ON_FAILURE環境變量設置為0以外的值。或者,您可以使用--gtest_break_on_failure命令行標志。

可用性:Linux,Windows,Mac。

 5.2 禁用捕獲測試 - 拋出異常Disabling Catching Test-Thrown Exceptions

   Google測試可以在啟用或不啟用exception的情況下使用。如果測試拋出C ++異常或(在Windows上)結構化異常(SEH),默認情況下Google測試會捕獲它,將其報告為測試失敗,並繼續執行下一個測試方法。這將最大化測試運行的覆蓋率。此外,在Windows上,未捕獲的異常將導致彈出窗口,因此捕獲異常允許您自動運行測試。

  然而,當調試測試失敗時,您可能希望異常由調試器處理,以便您可以在拋出異常時檢查調用堆棧。要實現此目的,請在運行測試時將GTEST_CATCH_EXCEPTIONS環境變量設置為0,或使用--gtest_catch_exceptions = 0標志。

 5.3 讓另一個測試框架驅動

    如果您使用的項目已經使用了另一個測試框架,但尚未准備好完全切換到Google測試,則可以通過在現有測試中使用其斷言來獲得Google測試的許多優勢。 只是改變你的main()函數看起來像:

#include "gtest/gtest.h"

int main(int argc, char** argv) {
  ::testing::GTEST_FLAG(throw_on_failure) = true;
  // Important: Google Test must be initialized.
  ::testing::InitGoogleTest(&argc, argv);

  ... whatever your existing testing framework requires ...
}

 這樣,除了你的框架提供的斷言之外,您還可以使用Google Test斷言,例如:

void TestFooDoesBar() {
  Foo foo;
  EXPECT_LE(foo.Bar(1), 100);     // A Google Test assertion.
  CPPUNIT_ASSERT(foo.IsEmpty());  // A native assertion.
}

。。。。。後邊的省略了,這個應該需要不到

6. 將測試功能分發到多台機器

如果您有多個機器可以用來運行測試程序,您可能希望並行運行測試功能並更快地獲得結果。我們稱之為技術分片,其中每台機器被稱為分片。

Google測試與測試分片兼容。要利用此功能,您的測試運行器(不是Google測試的一部分)需要執行以下操作:

您的項目可能有沒有Google Test的測試,因此不了解此協議。為了讓測試運行器確定哪個測試支持分片,它可以將環境變量GTEST_SHARD_STATUS_FILE設置為不存在的文件路徑。如果測試程序支持分片,它將創建此文件以確認事實(文件的實際內容此時不重要;雖然我們將來可能會在其中粘貼一些有用的信息。否則它不會創建它。

這裡有一個例子來說明。假設您有一個包含以下5個測試函數的測試程序foo_test:

TEST(A, V)
TEST(A, W)
TEST(B, X)
TEST(B, Y)
TEST(B, Z)

你有3台機器在您的處置。 要並行運行測試功能,您需要在所有機器上將GTEST_TOTAL_SHARDS設置為3,並將GTEST_SHARD_INDEX分別設置為0,1和2。 然後你將在每台機器上運行相同的foo_test。

Google測試有權更改工作在分片上的分布情況,但這裡有一種可能的情況:

  • Machine #0 runs A.V and B.X.
  • Machine #1 runs A.W and B.Y.
  • Machine #2 runs B.Z.

十二、融合Google測試源文件

  Google測試的實現包括〜30個文件(不包括自己的測試)。 有時你可能希望它們被打包在兩個文件(.h和.cc),以便你可以輕松地將它們復制到一個新的機器,並開始黑客。 為此,我們在scripts /目錄中提供了一個實驗性Python腳本fuse_gtest_files.py(自1.3.0版本開始)。 假設你在你的機器上安裝了Python 2.4或更高版本,只需去那個目錄並運行

   python fuse_gtest_files.py OUTPUT_DIR
  並且您應該看到一個OUTPUT_DIR目錄正在創建文件gtest / gtest.h和gtest / gtest-all.cc。 這些文件包含您使用Google測試所需的一切。 只需將它們復制到任何你想要的,你准備好寫測試。 您可以使用scripts / test / Makefile文件作為如何編譯針對它們的測試的示例。

 

上篇博文地址:Google C++單元測試框架GoogleTest---AdvancedGuide(譯文)上

轉載請注明出處:http://www.cnblogs.com/jycboy/p/AdvancedGuide2.html

 

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved