Q: 單元測試是需求"文檔", 單元測試又是設計"文檔", 它怎么能既是需求又是設計呢?
A: 名字和斷言描述需求, 環境設置描述設計 ...
Q: 既然單元測試描述的是需求, 它就應該是黑盒測試了? 可單元測試不一直都被認為是白盒測試嗎?
A: 黑白都是相對于你觀察的層次. 相對于其它從外部觀察"系統"行為, 不涉及源代碼的測試來說, 單元測試深入到內部觀察盒子的行為, 所以是白盒. 而具體到每個單元測試用例, 依然在盡可能的從外部觀察"單元"的行為, 所以又是黑盒.
Q: 但是你們常用的 Mock 技術, 明顯把單元測試推向白盒的境地.
A: 說來話長, 但可以先說結論: 基于狀態的測試 over 基于交互/行為的測試, 雖然右邊的也有巨大的價值, 但我們認為左邊的更穩定和更富有對系統的洞察力
基于狀態的測試描述的是需求, 基于交互行為的測試描述的是實現. 相對于需求來說, 實現更易發生變化, 尤其在另外一種實踐"重構"的沖擊下, 描述實現的測試將被修改的面目全非, 帶來相當的返工和維護成本
一種例外, 就是交互本身就是需求, 這時 mock 是合適的選擇. 一個杜撰的例子參見<<TDD: Tricky Driven Design 3, 方法>>中最后銀行API的例子
而現實生活中, 存在一些情況, 雖然使用 mock 可能帶來后期的維護成本, 但它帶來的好處也是不可代替的. 比如對先期整體測試代碼的編碼量的降低. 這在 C/C++ 項目中尤其明顯:
受限于C/C++的編譯模型, 使用常用的預處理期接入點和編譯鏈接接入點技術來接入 stub 實現時, 要小心維護頭文件的防衛宏, 頭文件的名稱, 不同環境下構建腳本的include路徑設置, 庫路徑設置等. 手工寫stub的方式變的及其繁瑣和容易出錯. 這時候, 一個易用的 mock 框架如 mockcpp 等將節省大量的編碼和先期維護工作
而幾乎所有的mock框架, 都支持將 mock 對象退化為 stub, 如 mockcpp 中 mock 對象的 defaults() 設置, 或者 JMock 2 中的 Allowing . 事實上, 這是我推薦的 mock 使用方式: 通常情況下讓它退化為簡單的stub, 必要時才使用它強大的期待設置和驗證能力.
通常單元測試有兩個公認的約束需要滿足:
-
快
-
隔離依賴.
重申一遍結論就是: 在滿足單元測試的快和隔離依賴的前提下,
-
優先選擇基于狀態的黑盒測試(可使用手寫stub或mock退化的stub)
-
除非交互和行為本身就是需求(可使用mock對象的全部特性)
文章來源于領測軟件測試網 http://www.kjueaiud.com/