2011-05-28 69 views
0

說我有下面的代碼,這是不能被修改:測試不友好的代碼

class A { 
    public doSomething() { 
     // lots of business logic 
     data = obtainData(); 
     // lots of other business logic which depends on data 
    } 

    private obtainData() { 
     // connect to the database 
     // send web requests 
     // send manned missions to the moon 
     // process the obtained data 
     return data; 
    } 
} 

什麼是測試這樣的代碼的最佳做法?我想確保doSomething()做它應該做的事情,但我想提供它與已知的數據,而不是運行obtainData()內的代碼。

+2

私人而不是保護......哎呀。:-( – 2011-05-28 11:20:59

+0

@Denis,確實... – rid 2011-05-28 11:21:45

+0

@Denis:私人有什麼問題? – zerkms 2011-05-28 11:22:31

回答

0

看一看Moles幫助您與棕地測試。 C#中的痣允許您爲私有代碼和其他人的代碼提供自己的實現。

當你有一個很好的一套覆蓋這個爛攤子測試,請re-factor拯救人類。

如果麪條代碼的鼻祖是指日可待,請嫌他對我,爲什麼不遐?

對於最佳實踐,閱讀Bob大叔的清潔守則http://www.amazon.com/Clean-Code-Handbook-Software-Craftsmanship/dp/0132350882

總結:如果被測代碼有外部依賴,使他們明確和外部配置。

+0

「布朗」聽起來恰到好處!我問的是一般的最佳實踐。這樣的東西如何用常規單元測試進行測試。 – rid 2011-05-28 11:29:36

+0

@rdineiu:原始問題沒有包含特定的語言或技術。我提供了一個通用的答案。 – GregC 2011-05-28 11:37:19

+0

@GregC,沒關係。通用就是我要求的。所以答案是,如果可能的話,最好的做法是將私有方法拆除並用其他方法替代,或者如果不可能,則不要進行測試。對? – rid 2011-05-28 11:39:57

-1

你看過Mocking嗎?它可能由您的單元測試框架提供。

+0

我知道嘲諷。但是,我將如何創建一個模擬測試這個類?我應該嘲笑什麼? – rid 2011-05-28 11:20:54

+0

部分模擬不適用於所有測試FW。在phpunit中沒有。 – zerkms 2011-05-28 11:21:11

0

你沒有張貼有問題的代碼,通常的罪魁禍首是在建築工創建新對象,靜態調用,使用常數,和其他幾個人。

這個想法是將你的類從它的依賴關係中分離出來。這樣做的常見方式是依賴注入。

還要考慮其較小的類,做的非常具體的任務,機會是,如果你描述你的類的任務與「和」的句子,它確實太多,將很難測試。

this post和所有它來測試靜態和硬編碼的依賴性相關鏈接相關信息。

+0

我在看,我正在考慮通過最新的PHP 5.3提供的黑巫術魔法訪問私有方法(我的代碼恰好是PHP),但這是處理這個問題的正確方法嗎?它不知何故似乎......非常醜陋......你如何以一種不提供暴露私人方法所必需的魔法的語言來做到這一點?或者你不會? – rid 2011-05-28 11:34:19

+0

有幾個職位我自己在這個確切的主題。你不應該測試你的私有方法和變量。有例外,但即使是那些反映了糟糕的設計。您應該測試公共方法,這些將驗證私人按預期工作。您將1.節省時間,2.擁有更有意義的代碼覆蓋率報告3.更多地享受單元測試的方式。 就像我說過的,要在一個類上測試太多的東西意味着需要將它分成具有不同責任的較小類,這樣可以更容易地模擬並減少此類的預期結果,從而減少測試次數。 – stefgosselin 2011-05-28 11:46:01

+0

你不必說服我,我是依賴注入和解耦的粉絲。但不幸的是,我們並不是生活在一個完美的世界,有時我們需要繼承糟糕的代碼(當我說*壞*,我是外交)。但它仍然需要進行測試...... – rid 2011-05-28 11:50:16

0

的設計

  1. 工作確定這個類的責任。
  2. 接下來,提取這個類的依賴關係。將所有不符合項目符號#1的方法移到依賴項中。

例如如果此類不負責處理數據庫或網絡IO,請將它們提取爲此類的依賴項。將它們注入爲參數或方法參數(如果只有一個公共方法需要它)。

public A(DataRepository repository, WebService service, SpaceStation spaceStation) 
{ // cache them as internal fields;} 

現在沒有必要存根出或子類,並覆蓋或增加測試的成員可見。

你的單元測試將創建一個實例作爲

_testSubject = new A(new Mock<DataRepository>.object, new Mock<WebService>.object, new Mock<SpaceStation>.object); 

,而你的產品代碼將使用上述角色的真正實現。

+0

這個想法是將你可以在你的測試中模擬/替換的角色背後的不友好的比特/笨拙的依賴移動。 – Gishu 2011-05-31 05:32:24