2010-11-01 82 views
3

我目前正在使用另一個只有靜態函數的類的類。測試依賴於另一個類的靜態函數的類

一切工作正常,直到我嘗試測試我的課程。

這是問題的一個簡單的代碼例如:

class A { 
    static String getSometing() { 
     return String("Something: ") + heavyCalculation().asString(); 
    } 
} 

class B { 
    B() {} 
    ~B() {} 
    String runSomething(const String& name) { 
     if(name.equals("something")) { 
      return A::getSomething(); 
     } else { 
      return "Invalid name!"; 
     } 
    } 
} 

假設類A是否正常工作(並且已經被它的單元測試測試),我想檢查在類runSomething功能B.

我的第一選擇是創建內部類(在這個例子 - A類)嘲笑,但在這種情況下,它會給我沒什麼可從A繼承,因爲它只有靜態功能。

我的第二個選擇是封裝在內部B私有函數的類的調用,所以我可以控制自己的返回值(雖然選擇此選項將使好一點點更復雜)。

我對你的問題是:是否有更好的方法來測試C++類取決於比我目前的選擇靜態類/功能?

由於提前,

塔爾。

回答

3

我已經在類似的情況下通過重構靜態函數的引用(在我的情況下它是外部依賴)到新的私有函數並覆蓋它們在測試存根上的單元測試中取得成功,所以我可以推薦這種方法

如果重構功能保持私密,他們不應該大大的設計的複雜性影響,他們應該是足夠小,不會產生負面的代碼的可讀性產生影響。

0

我會說,「男人,有些人採用單元測試的方式太過分了!」

只需將兩個類作爲一個單元進行測試即可。無論如何,A類都被硬編碼到B類中。

+2

如果需要30秒來執行該靜態函數會怎麼樣? – 2010-11-02 08:41:25

+0

@VJo:那麼你擔心解決這個問題。如果執行該功能需要0.0030秒,則您只需花費大量測試寫入時間。 – 2010-11-03 21:20:27

-1

你應該通過模板走班,並明確導出實例化(B<A>),以避免連接問題,如果張貼以前沒有所有內聯。這樣,您可以根據需要插入其他類以用於測試,無論如何都是很好的練習。我也很好奇爲什麼你的例子看起來像Java一樣 - 我必須在確定它實際上是 C++之前閱讀過它大約五次。

template<typename T> class BImpl { 
    String runSomething(const String& name) { 
     if(name.equals("something")) { 
      return T::getSomething(); 
     } else { 
      return "Invalid name!"; 
     } 
    } 
}; 
typedef BImpl<A> B; // Just plugs in to existing code. 

現在,即使無法繼承它,現在您也可以用模擬類替換A。事實上,這也可以用另一種方式擴展 - CRTP。

class A : public BImpl<A> { 
    String getSomething() { 
     // Now it's non-static! IT'S A MIRACLE! 
    } 
} 

模板的奇蹟永遠不會停止讓我驚歎。

1

如果你不使用單片測試套件,那麼它很容易。我假設你有A.cpp中的A類和B.cpp中的B類,並且B的測試在B_test.cpp中。

創建一個名爲A_mock的文件。cpp

class A 
{ 
    static String getSometing() { 
     return String("Expected Something"); 
    } 
}; 

然後編譯你的B_test文件時,只需要鏈接到A_mock.o而不是A.o。

g++ -Wall B_test.cpp B.cpp A_mock.cpp 
+0

這是可行的,而在非面向對象的代碼中往往是唯一可以應用的方法。但是,它確實導致函數的覆蓋與實際測試代碼分開,導致更復雜的維護方案 - 在原始編碼器之後出現的人不一定會認爲要查看makefile以找出正在調用的靜態函數。 – dlanod 2010-11-02 21:16:59

0

你可以一個函數指針傳遞給類A,然後進行測試的構造函數,你可以傳遞一些指針模擬功能,在這裏你可以做任何你想要的。

0

爲什麼靜態函數?我會建議不要把它變成靜態的。

然後,您可以創建一個名爲AInterface的類A(在C++中,這意味着一個只有純虛函數頭的類)的接口。 A類將實現(繼承)AInterface並實現這個虛函數。

然後將指向此接口的指針傳遞給B類的構造函數,並將其存儲在名爲m_A的成員變量中。然後在你的測試中,創建實現AInterface的MockClassA。將MockClassA傳入B類構造函數,並將m_A設置爲輸入。

class AInterface 
{ 
    virtual String getSomething() = 0; 
} 

class A : public AInterface 
{ 
    String getSometing() { 
     return String("Something: ") + heavyCalculation().asString(); 
    } 
} 

class B 
{ 
    B(AInterface A) : m_A(A) {} 
    ~B() {} 
    String runSomething(const String& name) { 
     if(name.equals("something")) { 
      return m_A::getSomething(); 
     } else { 
      return "Invalid name!"; 
     } 
    } 
    AInterface m_A; 
} 

void test() 
{ 
    auto instanceOfA = std::make_shared<A>(); 
    auto instanceOfB = std::make_shared<B>(instanceOfA); 

    String returnValue = instanceOfB.runSomething("something"); 
    : 
    : 
} 
相關問題