如果你發現自己寫了兩個或更多的測試來操作類似的數據,你可以使用測試夾具。它允許您為幾個不同的測試重復使用相同的對象配置。
要創建夾具,只需:
1.從:: testing :: Test派生一個類。 使用protected:或public:開始它的主體,因為我們想從子類 訪問fixture成員。
2.在類中,聲明你打算使用的任何對象。
3.如果需要,可以編寫默認構造函數或SetUp()函數來為每個測試准備對象。 一個常見的錯誤是 拼寫SetUp()為Setup()與一個小u -- 不要讓這種情況發生在你身上。
4.如果需要,寫一個析構函數或TearDown()函數來釋放你在SetUp()中分配的任何資源。 要 學習什麼時候應該使用構造函數/析構函數,當你應該使用SetUp()/ TearDown()時,請閱讀這個 FAQ entry.。
5.如果需要,定義要分享的測試的子程序。
當使用夾具時,使用TEST_F()而不是TEST(),因為它允許您訪問測試夾具中的對象和子程序:
TEST_F(test_case_name, test_name) { ... test body ... }
和TEST()一樣,第一個參數是測試用例名,但是對於TEST_F()必須是測試夾具類的名稱。 你可能猜到了:_F是夾具。
不幸的是,C ++宏系統不允許我們創建一個可以處理兩種類型的測試的宏。 使用錯誤的宏會導致編譯器錯誤。
另外,在TEST_F()中使用它之前,你必須首先定義一個測試夾具類,否則將得到編譯器錯誤“virtual outside class declaration”。
對於使用TEST_F()定義的每個測試,Google Test將:
1.在運行時創建一個新的測試夾具
2.立即通過SetUp()初始化,
3.運行測試
4.通過調用TearDown()清除
5.刪除測試夾具。 請注意,同一測試用例中的不同測試具有不同的測試夾具對象,Google測試始 終會刪除測試夾具,然後再創建下一個測試夾具。 Google測試不會為多個測試重復使用相同的 測試夾具。一個測試對夾具的任何更改不會影響其他測試。
例如,讓我們為名為Queue的FIFO隊列類編寫測試,它有以下接口:
template <typename E> // E is the element type. class Queue { public: Queue(); void Enqueue(const E& element); E* Dequeue(); // Returns NULL if the queue is empty. size_t size() const; ... };
首先定義一個夾具類。按照慣例,你應該給它名稱FooTest,其中Foo是被測試的類。
class QueueTest : public ::testing::Test { protected: virtual void SetUp() { q1_.Enqueue(1); q2_.Enqueue(2); q2_.Enqueue(3); } // virtual void TearDown() {} Queue<int> q0_; Queue<int> q1_; Queue<int> q2_; };
在這種情況下,不需要TearDown(),因為我們不必在每次測試後清理,除了析構函數已經做了什麼。
現在我們將使用TEST_F()和這個夾具編寫測試。
TEST_F(QueueTest, IsEmptyInitially) { EXPECT_EQ(0, q0_.size()); } TEST_F(QueueTest, DequeueWorks) { int* n = q0_.Dequeue(); EXPECT_EQ(NULL, n); n = q1_.Dequeue(); ASSERT_TRUE(n != NULL); EXPECT_EQ(1, *n); EXPECT_EQ(0, q1_.size()); delete n; n = q2_.Dequeue(); ASSERT_TRUE(n != NULL); EXPECT_EQ(2, *n); EXPECT_EQ(1, q2_.size()); delete n; }
上面使用ASSERT_ *和EXPECT_ *斷言。 經驗法則( The rule of thumb )是當你希望測試在斷言失敗後繼續顯示更多錯誤時使用EXPECT_ *,或是在失敗後繼續使用ASSERT_ *沒有意義。 例如,Dequeue測試中的第二個斷言是ASSERT_TRUE(n!= NULL),因為我們需要稍後解引用指針n,這將導致n為NULL時的segfault。
當這些測試運行時,會發生以下情況:
1.Google Test構造了一個QueueTest對象(我們稱之為t1)。
2.t1.SetUp()初始化t1。
3.第一個測試(IsEmptyInitially)在t1上運行。
4.t1.TearDown()在測試完成後清理。
5.t1被析構。
6.以上步驟在另一個QueueTest對象上重復,這次運行DequeueWorks測試。
1. 當定義測試夾具時,您指定將使用此夾具的測試用例的名稱。 因此,測試夾具只能由一個測試用例使用。
有時,多個測試用例可能需要使用相同或稍微不同的測試夾具。 例如,您可能需要確保GUI庫的所有測試不會洩漏重要的系統資源,如字體和畫筆。 在Google測試中,您可以做到
這通過將共享邏輯放在超級(如“超級類”)測試夾具中,然後讓每個測試用例使用從這個超級夾具派生的夾具。
在這個示例中,我們希望確保每個測試在〜5秒內完成。 如果測試運行時間較長,我們認為測試失敗。
我們把測試時間的代碼放在一個叫做“QuickTest”的測試夾具中。 QuickTest旨在作為其他夾具派生的超級夾具,因此沒有名為“QuickTest”的測試用例。
然後,我們將從QuickTest中導出多個測試夾具。
class QuickTest : public testing::Test { protected: // Remember that SetUp() is run immediately before a test starts. // This is a good place to record the start time. //這個方法在每一個test之前執行 virtual void SetUp() { start_time_ = time(NULL); } // TearDown() is invoked immediately after a test finishes. Here we // check if the test was too slow. //這個方法在每一個test之後執行 virtual void TearDown() { // Gets the time when the test finishes const time_t end_time = time(NULL); // Asserts that the test took no more than ~5 seconds. Did you // know that you can use assertions in SetUp() and TearDown() as // well? EXPECT_TRUE(end_time - start_time_ <= 5) << "The test took too long."; } // The UTC time (in seconds) when the test starts time_t start_time_; };
2.我們定義一個IntegerFunctionTest繼承QuickTest, 使用該夾具的所有測試將自動要求快速。
class IntegerFunctionTest : public QuickTest { // We don't need any more logic than already in the QuickTest fixture. // Therefore the body is empty. };
3.現在我們可以在Integer Function Test測試用例中寫測試了。
TEST_F(IntegerFunctionTest, Factorial) { // Tests factorial of negative numbers. EXPECT_EQ(1, Factorial(-5)); EXPECT_EQ(1, Factorial(-1)); EXPECT_GT(Factorial(-10), 0); // Tests factorial of 0. EXPECT_EQ(1, Factorial(0)); // Tests factorial of positive numbers. EXPECT_EQ(1, Factorial(1)); EXPECT_EQ(2, Factorial(2)); EXPECT_EQ(6, Factorial(3)); EXPECT_EQ(40320, Factorial(8)); }
4. 下一個測試用例(名為“QueueTest”)也需要很快,所以我們從QuickTest派生另一個夾具。
QueueTest測試夾具有一些邏輯和共享對象,除了QuickTest中已有的。 我們像往常一樣在測試夾具的主體內定義額外的東西。
class QueueTest : public QuickTest { protected: virtual void SetUp() { // First, we need to set up the super fixture (QuickTest). QuickTest::SetUp(); // Second, some additional setup for this fixture. q1_.Enqueue(1); q2_.Enqueue(2); q2_.Enqueue(3); } // By default, TearDown() inherits the behavior of // QuickTest::TearDown(). As we have no additional cleaning work // for QueueTest, we omit it here. // // virtual void TearDown() { // QuickTest::TearDown(); // } Queue<int> q0_; Queue<int> q1_; Queue<int> q2_; };
接下來我們就可以用QueueTest寫一些測試。
// Tests the default constructor. TEST_F(QueueTest, DefaultConstructor) { EXPECT_EQ(0u, q0_.Size()); }
如有必要,您可以從派生的夾具本身獲得進一步的測試夾具。 例如,您可以從QueueTest派生另一個夾具。 Google測試對層次結構的深度沒有限制。 然而,在實踐中,你可能不希望它太深以至於混淆。