一、測試夾具(Test Fixtures):對多個測試使用相同的數據配置
如果你發現自己寫了兩個或更多的測試來操作類似的數據,你可以使用測試夾具。它允許您為幾個不同的測試重復使用相同的對象配置。
要創建夾具,只需:
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測試對層次結構的深度沒有限制。 然而,在實踐中,你可能不希望它太深以至於混淆。
