SQL 單元測試應該這麼長嗎?
我正在編寫具有一些重要業務邏輯的儲存過程。我正在嘗試對它們進行單元測試,但實際測試最終會很長(較短的測試從 40-50 LoCs 開始,通常使用 4 個不同的表),這似乎不是很“單元”。(誠然,我以一種佔用大量空間的方式格式化我的程式碼。)
在“普通”程式語言的上下文中,我聽說過將復雜過程重構為更小的塊的建議。但我不想在這裡這樣做,因為:
- 我不想只從一個地方呼叫的小常式污染“全域命名空間”。
- 在儲存過程之間傳遞表是很麻煩的。
- 自定義函式可能會對性能產生負面影響。
我對這個推理有誤嗎?我是單元測試的新手,所以也許我只是寫錯了我的測試?SQL 是冗長的語言,因此它的單元測試也更長嗎?
(我正在使用帶有 tSQLt 框架的 SQL Server,但我相信這個問題與系統無關。)
我對這個推理有誤嗎?我是單元測試的新手,所以也許我只是寫錯了我的測試?SQL 是冗長的語言,因此它的單元測試也更長嗎?
我認為這是一個很好的(雖然有點基於意見)的問題。在過去的幾年中,我嘗試在個人 OSS 項目 ( https://dba-multitool.org/ ) 中實現 tSQLt 單元測試,以嘗試通過現實世界的應用程序來回答它。任何類型的 SQL 的單元測試肯定會打破經典的規範和模式。我的測試絕對不像單元測試,而且通常比我想要的更複雜/更長,但它們讓我免於引入重大更改。
我的範例中的儲存過程非常複雜且冗長,因此我遇到了與您類似的僵局:我應該把它吸收並處理非常複雜的“單元”測試,還是從根本上修改儲存過程的工作方式,使其更加一般對單元測試友好嗎?與許多數據庫問題一樣,我相信最終的答案*取決於它。*以我的經驗,性能和可維護性在這裡佔據首位。
我發現我無法證明在很大程度上改變複雜的儲存過程以從單元測試中受益 - 正如您所指出的,添加更多對象會增加複雜性,在這種情況下,我很謹慎地要求最終使用者容納一堆單一的- 在他們的數據庫中使用對象,而不是提供一個多合一的實用程序儲存過程。
我確實提出的一種技術是使用可選參數來更好地引入測試案例。例如,我有參數
@IsExpress
,@SqlMajorVersion
, 並且@SqlMinorVersion
最終使用者不應使用(如果未通過,則在執行時獲取它們)但我的測試使用以確保在不受支持的版本中發現我想要的錯誤。添加大量錯誤將提高程式碼的整體可靠性,而不必明確測試可能難以/不合理的更複雜的邏輯區域。這略微影響了儲存過程的長度和復雜性,但讓我可以輕鬆地隔離功能並對其進行可靠的測試。您可以更進一步並使用參數來觸發儲存過程中最需要測試的部分,或者通過避免不值得覆蓋或超出範圍的雜亂區域來實現更好的程式碼覆蓋率。通過這種方法,我能夠獲得相當高的程式碼覆蓋率(98%+),雖然我絕對不會測試所有功能,但我知道幾乎所有程式碼都會被執行,當我需要它時會出錯,並且會在執行時解析。
最後引用一句,維基百科將單元測試定義為(強調我的):
在電腦程式中,單元測試是一種軟體測試方法,通過該方法對原始碼的各個單元(一個或多個電腦程序模組的集合以及相關的控制數據、使用程序和操作程序)進行測試以確定它們是否適合使用.
我不會說 Wikipedia(或 Wikipedia 引用的書)是技術定義的終極目標,但我確實喜歡這個定義,因為它側重於單元測試的最終目標,我認為 tSQLt 可以合理地實現。
此外,一些單元測試總比沒有好,並且定義單元測試未涵蓋的程式碼行在將來可能非常有價值。擴展後者:
在 3 年內,您離開了公司,員工 #948 正試圖解決儲存過程中的錯誤。他們看了看,只有 300 行中的第 50-65 行沒有被單元測試覆蓋,否則所有其他功能都已經過測試。他們現在有很好的機會將時間花在可能有問題的區域上,而不是對整個 300 行進行逆向工程。或者,可以要求下一個實習生/新員工填補缺少的單元測試覆蓋空白作為學習練習。了解您尚未測試的內容有助於確定未來工作的優先級並更快地診斷問題。