2011-10-06 79 views
11

我使用googletest來實現測試開始,在文檔中橫跨這句話無意中發現關於value-parameterized tests數據驅動測試不好嗎?

  • 要測試在各種輸入您的密碼(又稱爲數據驅動 測試)。這個功能很容易被濫用,所以請在做這件事時練習一下你的好感 !

我覺得做以下,並想聽聽你對此事的投入和意見時,我確實是「濫用」的系統。

假設我們有以下代碼:

template<typename T> 
struct SumMethod { 
    T op(T x, T y) { return x + y; } 
}; 

// optimized function to handle different input array sizes 
// in the most efficient way 
template<typename T, class Method> 
T f(T input[], int size) { 
    Method m; 
    T result = (T) 0; 
    if(size <= 128) { 
     // use m.op() to compute result etc. 
     return result; 
    } 
    if(size <= 256) { 
     // use m.op() to compute result etc. 
     return result; 
    } 
    // ... 
} 

// naive and correct, but slow alternative implementation of f() 
template<typename T, class Method> 
T f_alt(T input[], int size); 

好了,所以與此代碼,它當然具有隨機產生的數據,以測試的不同的輸入數組大小有意義(通過用f_alt()比較)來測試f()分支機構的正確性。最重要的是,我有幾個structsSumMethodMultiplyMethod等,所以我運行相當大量的試驗也爲不同的類型:

typedef MultiplyMethod<int> MultInt; 
typedef SumMethod<int> SumInt; 
typedef MultiplyMethod<float> MultFlt; 
// ... 
ASSERT(f<int, MultInt>(int_in, 128), f_alt<int, MultInt>(int_in, 128)); 
ASSERT(f<int, MultInt>(int_in, 256), f_alt<int, MultInt>(int_in, 256)); 
// ... 
ASSERT(f<int, SumInt>(int_in, 128), f_alt<int, SumInt>(int_in, 128)); 
ASSERT(f<int, SumInt>(int_in, 256), f_alt<int, SumInt>(int_in, 256)); 
// ... 
const float ep = 1e-6; 
ASSERT_NEAR(f<float, MultFlt>(flt_in, 128), f_alt<float, MultFlt>(flt_in, 128), ep); 
ASSERT_NEAR(f<float, MultFlt>(flt_in, 256), f_alt<float, MultFlt>(flt_in, 256), ep); 
// ... 

當然現在我的問題是:這樣的任何意義,爲什麼這會很糟糕?

事實上,我曾與float正在競選測試時,其中f()f_alt()將給予不同的價值觀與SumMethod由於四捨五入的原因,我可以通過預分類輸入數組等提高發現了一個「錯誤」。從這個經驗我認爲這實際上是一種很好的做法。

回答

10

我認爲主要問題是測試「隨機生成的數據」。從您的問題中不清楚,每次運行測試工具時是否重新生成這些數據。如果是,那麼你的測試結果是不可重現的。如果一些測試失敗了,它會在你每次運行時都失敗,而不是在藍色的月亮中運行一次,在一些奇怪的隨機測試數據組合上。

所以在我看來,您應該預先生成測試數據並將其保存爲測試套件的一部分。您還需要確保數據集足夠大且多樣化,以提供足夠的代碼覆蓋率。此外,正如Ben Voigt在下面評論的那樣,僅使用隨機數據測試是不夠的。您需要確定算法中的角落案例並分別進行測試,並針對這些案例量身定製數據。但是,在我看來,如果您不確定是否知道所有角落案例,那麼使用隨機數據進行附加測試也是有益的。你可以用隨機數據偶然擊中它們。

+2

由於兩個原因,隨機生成的數據不好 - 首先,因爲如您所述,測試不可重現。其次,因爲角落案件可能不會被隨機生成的數據覆蓋。第二個缺點是保存隨機向量不會起任何作用。 –

+0

謝謝。我修改了我的答案,你當然是對的。 – haimg

+0

@haimg - 如果你在做黑箱測試,你怎麼知道使用的算法和它的角落案例? :-) –

6

問題是,你不能像浮點數一樣在Float上聲明正確性。

檢查某個epsilon內的正確性,這是計算值與期望值之間的小差異。這是你能做的最好的。對於所有浮點數都是如此。

我想我確實是這樣做的時候「濫用」系統的後續

你認爲你閱讀本文之前,這是壞?你能說清楚它有什麼不好嗎?

您必須在某個時間測試此功能。你需要數據來做到這一點。虐待在哪裏?

+0

當然。在上面的例子中我忘記了正確的。編輯。除此之外,我對反對寫這種測試的論點更感興趣。 – bbtrb

0

數據驅動測試很難維護,並且在較長的一段時間內,在測試本身中引入錯誤更容易。 詳情請看:http://googletesting.blogspot.com/2008/09/tott-data-driven-traps.html

從我的觀點單元測試點

而且是最有用的,當你正在做認真重構和你不知道,如果你沒有在錯誤的方式改變的邏輯。 如果你的隨機數據測試在這種改變之後會失敗,那麼你可以猜測:是因爲數據還是因爲你的改變?

然而,我認爲它可能是有用的(壓力測試也不是100%可重複)。但是,如果您正在使用一些持續集成系統,我不確定是否應該將包含大量隨機生成數據的數據驅動測試納入其中。 我寧願單獨部署,因爲它會立刻使很多隨機測試(所以每次運行時發現不好的事情的機會應該是相當高的)。但是它像正常測試套件那樣佔用資源太多。