在最近的一次採訪中,有人問我爲什麼要創建模擬對象。我的回答是這樣的:「拿一個數據庫 - 如果你正在編寫測試代碼,你可能不希望這個測試直接連接到將要執行實際操作的生產數據庫。」爲什麼要創建模擬對象?
通過回答來判斷,我的回答顯然不是面試官所期待的。什麼是更好的答案?
在最近的一次採訪中,有人問我爲什麼要創建模擬對象。我的回答是這樣的:「拿一個數據庫 - 如果你正在編寫測試代碼,你可能不希望這個測試直接連接到將要執行實際操作的生產數據庫。」爲什麼要創建模擬對象?
通過回答來判斷,我的回答顯然不是面試官所期待的。什麼是更好的答案?
我總結是這樣的:
在接受記者採訪時,我建議包括嘲弄,甚至更好,當開發人員使用依賴注入,一旦它允許你有更多的控制權,並且更容易構建測試。
模擬對象/函數在團隊中工作時也很有用。如果你正在研究代碼庫的一部分,而這部分代碼庫依賴於其他人負責的代碼庫的不同部分 - 仍在編寫或尚未編寫 - 模擬對象/函數對於給你一個預期的輸出,這樣你就可以繼續工作而不用等待對方完成任務。
當單元測試時,每個測試的目的都是爲了測試單個對象。然而,系統中的大多數對象都會有其他對象進行交互。模擬對象是這些其他對象的虛擬實現,用於隔離被測對象。
這樣做的好處是任何失敗的單元測試通常都會將問題與被測對象隔離開來。在某些情況下,問題將出現在模擬對象上,但這些問題應該更容易識別和修復。
爲模擬對象編寫一些簡單的單元測試也是一個想法。
它們通常用於創建模擬數據訪問層,以便單元測試可以獨立於數據存儲運行。
當以MVC模式測試控制器對象時,其他用途可能會模擬用戶界面。這允許更好地自動測試UI組件,這可以在一定程度上模擬用戶交互。
一個例子:
public interface IPersonDAO
{
Person FindById(int id);
int Count();
}
public class MockPersonDAO : IPersonDAO
{
// public so the set of people can be loaded by the unit test
public Dictionary<int, Person> _DataStore;
public MockPersonDAO()
{
_DataStore = new Dictionary<int, Person>();
}
public Person FindById(int id)
{
return _DataStore[id];
}
public int Count()
{
return _DataStore.Count;
}
}
只是爲了添加到這裏高檔的答案,模仿對象是在自上而下或自下而上的結構編程(OOP太)使用。他們在那裏爲上層模塊(GUI,邏輯處理)提供數據或充當模擬輸出。
考慮自頂向下的方法:首先開發GUI,但GUI應該有數據。所以你創建一個模擬數據庫,它只是返回一個std :: vector數據的向量<。你已經定義了這種關係的'契約'。誰在乎數據庫對象的內部發生的事情 - 只要我的GUI名單得到一個std ::矢量<>我很高興。這可以提供模擬用戶登錄信息,無論您需要如何使GUI工作。
考慮一種自下而上的方法。你寫了一個解析器來讀取分隔文本文件。你怎麼知道它是否工作?您爲這些對象編寫一個模擬「數據接收器」,並將數據發送到那裏以驗證(通常是)數據是否正確讀取。下一級的模塊可能需要2個數據源,但您只寫了一個。
在定義模擬對象的同時,您還定義了關係如何的合約。這通常用於測試驅動編程。您編寫測試用例,使用模擬對象來使其工作,並且通常不會,模擬對象的接口變成最終接口(這就是爲什麼在某些時候您可能希望將模擬對象的接口分離爲純粹的抽象類) 。
希望這有助於
這裏是a few situations where mocking is indispensabl E:
+1感謝您的鏈接 – k3b 2010-12-15 08:49:01
我會在這裏走了不同的方向。成株/假裝做上述所有的東西,但也許面試官在想嘲弄爲使測試通過或失敗的一個假的對象。我基於這個xUnit terminology。這可能會導致關於state testing verses behavior/interaction testing的一些討論。
他們可能一直在尋找的答案是:模擬對象是不是存根不同。存根模擬了被測方法的依賴關係。存根不應導致測試失敗。有模擬做這個和還檢查怎樣及何時被調用。基於潛在行爲,Mock會導致測試通過或失敗。這有利於在測試過程中減少對數據的依賴,但更貼近實施該方法。
當然,這是炒作,它更可能他們只是想你描述磕碰和DI的好處。
採取一種不同的方法(如我想嘲笑已經很好地覆蓋以上):
「把一個數據庫 - 如果你正在寫測試代碼,您可能不希望該測試迷上了活到生產數據庫,其中將執行實際操作。「
IMO是一種不好的方法來說明這個例子的用法,在測試中有或沒有模擬過程中,你永遠不會把它」連接到prod數據庫「,每個開發者都應該有一個開發者本地數據庫來測試。你可能會在測試環境數據庫,然後可能是UAT,並最終推動你不是在嘲笑避免使用實時數據庫,你是在嘲笑,以便不直接依賴於數據庫的類不要求你設置數據庫。
最後(我接受我可能會得到這方面的一些評論)IMO開發本地數據庫是在單元測試中創下了有效的東西,你應該只被擊中它在測試代碼直接與數據庫,並使用嘲笑交互當你te時刺痛間接訪問數據庫的代碼。
當然,在Mock Objects的*糟糕的一面,事實是,當真正的類接口發生變化時,有人必須運行查找和更新Mocks,同時所有這些「成功」的測試都是謊言。 – 2009-09-12 04:00:13
如果其中一個測試包括驗證界面未更改,則可以減輕此影響。那次測試失敗了,你知道你的模擬會出錯。 – 2009-12-09 23:39:18
但它並沒有改變接口的用戶損壞的事實。 – Gutzofter 2010-05-16 01:30:57