2009-07-14 30 views
21

爲了能夠單元測試我的C++代碼,我通常會傳遞被測試類的構造函數一個或多個可以是「生產代碼」或假/模擬對象的對象(讓我們調用這些注射物體)。我已通過C++中用於依賴注入的接口vs模板

  1. 創建了「生產代碼」類和假/模擬類繼承的接口。
  2. 使被測試的類成爲模板類,該類將注入對象的類型作爲模板參數,並將注入對象的實例作爲參數傳遞給構造函數。

一些隨機的想法:

  • ,直到我們有概念(C++ 0x中),只有文件和參數的命名會提示什麼提供被測類(使用模板時)。
  • 它並不總是能夠創造遺留代碼的接口
  • 的接口基本上只創建能夠做到依賴注入
  • 以同樣的方式:模板測試類只是做使依賴注入

你有什麼想法?這個問題還有其他解決方案嗎?

回答

4

我覺得界面選項比較好,但是不需要爲了測試而創建公共基類。您可以從生產類繼承您的模擬類並覆蓋必要的方法。你必須使這些方法變得虛擬,但這就是mockpp這樣的工具的工作原理,它們也允許將這個過程自動化一點點。

+0

這很簡單,但非常強大。我喜歡! – 2009-07-15 14:48:11

+4

爲了記錄,人們應該意識到使方法變爲虛擬問題(參見非虛擬接口(NVI)習語) – 2009-08-29 23:10:34

+1

是的,有時這種方法可能會與「純粹的NVI」發生衝突。在很多情況下,你可以嘲笑受保護的虛擬函數,但是如果你確實需要模擬公共的非虛擬接口,那麼我認爲它不會讓公衆虛擬化,並且仍然使用NVI。在這種情況下,人們會失去一些編譯器執行的最佳實踐,但本身並不是最佳實踐。 – 2009-09-01 22:57:55

8

用C++,還有另一種選擇 - 你給你的mock類完全相同的名稱作爲真正的類,和鏈接單元測試時,只需用mock對象/庫文件,而不是以假亂真將它們鏈接。

+1

理論上是。但我認爲這在實踐中不會很好。例如。你想在一次測試中模擬的班級可能會在另一次測試中被測試。然後,你需要爲每個測試套件或類似的東西創建一個單獨的項目(VS項目,例如)... – 2009-07-14 21:14:15

+1

非常多的是。我只是爲了適應測試框架而對代碼重大變化(例如接口和DI,即使它們沒有真正意義的地方)有很強烈的反感。無論如何,我可以告訴你,這個方案在實踐中確實有效(我已經看到它在生產中成功使用),儘管它需要更多樣板 - 但至少它不在代碼本身! – 2009-07-14 22:40:22

+0

我同意。我將不得不調查一下它對我們會造成的後果。也許一些魔法可以應用到VS項目中以使其更容易。 – 2009-07-15 14:55:10

3

模板將有運行時略少的性能損失(減少間接性,更少的電話,更多的在線優化),但將讓你受苦了編譯時間非常高的懲罰......

我認爲,爲了這個目的,接口更好(直到我們在C++ 0x TR1中有概念)......除非你不能減慢一些「瓶頸代碼」。接口在運行時更具動態性和可切換性。

記住,你可以構造具有默認的注射對象(以假亂真)類,但你可以有注入你的測試模擬那些工廠......你甚至都不需要繼承。

+1

能否詳細說明最後一段?你會如何使用工廠來注入模擬對象? – 2009-07-15 14:56:30

+0

http://msdn.microsoft.com/en-us/magazine/cc163739.aspx – 2009-07-16 20:43:09

+1

簡而言之:您可以擁有一個創建所有內部所需對象的單體工廠,並且您可以將該工廠替換爲創建模擬工廠對象在你的測試中 – 2009-07-16 20:44:59

2

不知道是否有幫助,但你可以有模板的構造函數:

struct Class_Under_Test 
{ 
    template <typename Injected> 
    Class_Under_Test() 
    { 
     ... 

    // and even specialize them 
    template <> 
    Class_Under_Test <A_Specific_Injection_Class> 
    { 
     ... 

只有實際使用會得到包括一個。