2014-09-10 73 views
1

我進入一個項目,我們有一個大的代碼庫,目前它沒有任何單元測試框架。我們正在處理的代碼將最終運行在一個框上,交換機/路由器/防火牆。Gtest與大C和C++代碼庫

所以我正在研究一段需要使用Gtest進行單元測試的代碼。 我有這個問題是嘲笑變量以測試函數本身。 例如,我有一個函數,它使用4個指針指向不同的對象,並使用幾個全局變量。爲了測試代碼中的不同路徑,我需要初始化因變量的幾乎整個狀態machien/values。 增加了複雜性,因爲它在大型代碼庫中是真實的,我寫的這個函數/方法使用了一些其他需要測試的例程/方法。每個人都需要進行單向測試,每個人都有自己的依賴關係。 我不確定我是否正在處理這個問題,或者gtest可能不是測試這種大型代碼庫的正確工具。

如果任何人有發言權測試經驗說調用堆棧說

function A { 
    code 
    code 
    function B 
    code 
    code 
    function C 
    code 
} 

function B 
{ 
    function D 
    code 
    function E 
} 

function C{ 
    code 
    function F 
    function G 
    code 
} 

像this.How做我測試所有這些功能,A-F?什麼是好策略?

+0

爲什麼在編寫C代碼時標記爲C++?順便說一下全局變量是一個壞主意 – 2014-09-10 19:06:03

+0

代碼庫有C和C++兩種,我知道全局變量是一個壞主意。這就是它現在的設計方法。要忍受它:) – 2014-09-10 20:18:50

+0

測試大型/複雜代碼是不容易的。您需要編寫能夠處理代碼的測試,並且經常設置各種對象。在我工作的地方,編寫測試的時間通常是實際開發真實代碼所需時間的2-5倍。只有當測試代碼非常簡單時,這個數字纔會下降到1.5或2倍。有時測試代碼可能需要10次以上的原始代碼寫入。 – 2014-09-10 20:20:35

回答

2

首先是重構代碼,以便可檢測的部分被隔離。特別是,這意味着刪除對全局變量的訪問。例如:

int global; 
int function() { 
    int r = foo(); 
    global += r/2; 
    bar(r); 
    return 42; 
} 

卸下全局對象裝置將其轉換爲一個輸入參數:

int real_function(int* target) { 
    assert(target); 
    int r = foo(); 
    *target += r/2; 
    bar(r); 
    return 42; 
} 

當然然後將其餘的代碼將停止編譯,所以在添加向後兼容性cludge:

int global_bar; 
// @deprecated, use real_function() directly 
int function() { 
    return real_function(&global_bar); 
} 

使用它,你會加緊調用鏈,提取依賴關係,並希望有一天刪除最後一次調用需要全局變量的變體。與此同時,您可以編寫不再依賴於全局資源的函數的測試。請注意,對於C++,您將使用引用而不是指針,並可能將所需的外部對象傳遞給類構造函數。這也被稱爲依賴注入,確保研究這個術語以獲得透徹的理解。

測試接觸全局變量函數的另一種方法是使用測試的設置函數將全局重置爲已知狀態。這仍然需要在全球進行聯繫,但這可能很困難。不使用全局變量可能會使代碼庫變得更好,因此接受它也會發送錯誤的消息。

+0

有一點需要注意的是,另外將相關的全局變量分組到結構中將有助於減少需要傳遞給函數的參數數量。如果不這樣做,您可以輕鬆完成佔用大量參數的功能。 – 2014-09-11 06:25:11

+0

在全局代碼中需要注意的另一件事是以函數靜態變量或線程局部變量的形式「隱藏的全局變量」。 – 2014-09-11 06:28:42

0

Ulrich Eckhardt基本上說:「你需要擺脫全局變量來製作易於測試的代碼」。但你真的應該走得更遠。

對於你想測試你應該看看

  • 它訪問全局的任何全局函數。
  • 它使用的參數。
  • 它調用的函數。

然後考慮:

  • 轉換它調用來調用一個或多個接口的功能,並且通過那些作爲參數。
  • 將全局變量轉換爲參數或接口上的函數調用。

如果你的函數是一個對象,而不是全局函數上的功能,您還可以考慮:

  • 使全局成員變量,並將它們傳遞給構造
  • 使得功能它調用虛擬成員函數

我認爲做一個函數可測試的最後一件事是它是否屬於一個類。

一旦解決了所有這些問題,您通常可以輕鬆地嘲弄所需的位。如果你使用gtest,你可以使用gmock來簡化這個過程。 (我之前使用過gtest和gtest,並且它非常無痛)

(是的,我在大規模代碼基礎上採用了這種方法......它通常很痛苦,但一旦得到習慣了它,代碼開始得到更多的測試 - 事情會改善。)