分布式系統測試
單元測試
分布式系統的開發工作通常會被劃分成多個模塊,由不同的開發人員分別編寫程序,所以代碼的單元測試工作通常是針對單個模塊進行的。如果模塊是獨立的,并 且功能集足夠小,單元測試是很容易做的,構造一組case,盡量覆蓋所有的分支基本上就OK。但實際上分布式系統里很少有完全獨立的模塊,大部分的模塊都 會跟其他的模塊有依賴關系或是網絡通信等。
對于有依賴的模塊的單元測試,理想情況下,依賴的模塊都已經準備好,并且被測試過沒有問題 (這個實際上是做不到的,而且模塊間有時還會存在相互依賴的情況),這種理想情況會嚴重影響開發效率,使得有依賴的模塊就只能串行開發測試。另外,如果依 賴的模塊在安裝、部署上需要花費很長的時間(比如是一個配置比較麻煩的server),那么每次單元測試都需要把server部署起來,測試成本是很高的。
實際單元測試的過程中,我們經常會把依賴其他模塊的地方用簡單的代碼代替,也就是做mock。最直觀的mock方式就是通過宏來控制,即如果是以 DEBUG模式運行,執行某段簡單的代碼(mock),如果非DEBUG模式運行,則執行實際的代碼邏輯。比如通過下面一段代碼把“從網絡上獲取數據”在 DEBUG模式運行時替換為“從本地內存獲取數據”,那么在執行單元測試時,我們就不需要依賴網絡的對端來提供數據,從而方便的測試代碼邏輯。而實際 fetch_data_from_network()的測試可延遲到功能測試階段。
#ifndef DEBUG_MODE fetch_data_from_network(); #else fetch_data_from_local_memory(); #fi |
使用宏來控制有時會使得代碼讀起來很混亂,如果是使用C++開發(或其他面向對象編程語言),更好的方式是借助多態的性質來做mock,如下面一段代 碼,DataManager是一個負責管理數據的類,它需要從網絡上其他的服務里獲取數據,MockDataManager是一個繼承自 DataManager的類,它從本地內存獲取數據,在測試時,我們可以將DataManager的實例換成MockDataManager的實例來運行 (必須是指針或是引用),這樣思路跟前面的思路其實是一樣的,只不過借助多態,更清晰明了,需要做的事情更少。google test和google mock是開源的測試、以及mock框架,使用他們會使你的測試工作更簡單,更有趣。
class DataManager { class MockDataManager : public DataManager { |
測試久了之后,你會發現測試的工作量往往跟代碼結構的設計有很大的關系,如果代碼結構本身毫無章法,再加進去一堆為單元測試而寫的代碼邏輯,只會令代碼 看起來更加糟糕;如果設計之初就考慮測試需求,盡量把業務與邏輯層次分開降低模塊間依賴性,把可能需要mock測試的地方設計為虛基類等,在做測試的時候 需要做的工作就會很少,而且測試新增代碼不會打亂現在的代碼邏輯結構。