原創|行業資訊|編輯:龔雪|2015-10-14 13:29:35.000|閱讀 398 次
概述:在這里向大家分享一些測試數據庫時的一些方法,并指出這些方法各自的優點和缺點。最后還介紹了一個新的測試方法,大家可以一起探討和學習。
# 界面/圖表報表/文檔/IDE等千款熱門軟控件火熱銷售中 >>
當我們提到數據庫測試時,有一件事是公認的:這不是一件容易的事。在最近一期的JAX雜志中,代表JAX發言的測試大師Colin Vipurs總結了測試數據庫常用方法的優點和缺點。
在我從事軟件開發的這些年,曾在許多不同的數據庫上執行過各種級別和類型的測試實例,其中包括RDBMS和NoSQL。它們有一個共同點——很難。因此,我在這里向大家分享一些測試數據庫時的一些方法,并指出這些方法各自的優點和缺點。
這種方法我過去常用,但現在我不建議大家繼續使用。在我的《測試也需要熱愛》(《Tests Need Love Too》)一書中,詳細討論了為什么決不能模擬任何第三方接口。沒看過這本書也沒有關系,我會在這里再次強調一遍。
一般情況下,你會用你認為的方式去模擬第三方接口的代碼,但其實你并不知道它真正的代碼是什么。這一點很重要,它很可能會導致錯誤的出現。除非你有更高級別的測試覆蓋你的代碼,但結果出來之前你沒法確定這樣的級別。此外,模擬原始JDBC真的很難。例如,測試示例1中的那小段代碼。
在這個測試中,不僅需要大量的預期設置,還需要驗證所有的請求都有正確的響應,jMock “states”被廣泛使用。由于JDBC工作方式的限制,這個步驟違反了模擬測試的規則——不能越過當前的級別進行測試模擬。所以,即使你的測試結果表明所有工作都可以正常進行,但是當按照這樣的代碼進行生產時還是會出現錯誤。
這聽起來好像很瘋狂,但這是最好的方法來驗證數據庫之間代碼的交互是否按照預期運行的。同樣,你還要確保你使用了正確的API。這種技術可以做到模式測試永遠不可能完成的效果,例如,使你的SQL語法正確并達到你預期的效果。
內存數據庫:使用e.g.H2內存版本,這是設置數據庫測試的一個最簡單快捷的方式。如果你愿意為你的代碼引入Spring,那么測試設置也會變得一樣簡單。
這段代碼創建了一個H2數據庫實例,并加載了在schema.sql和test-data.sql的測試數據中定義的模式。返回對象工具為javax.sql。使得源數據可以直接進入到需要它的類別中去。
這個方法的好處之一是快。你可以為你的每個測試需求建立一個新的數據庫,為你得到的數據準確性提供堅實的保障。這些都可以在JVM中完成,因此你的開發平臺上不需要額外的基礎設施。
這種方法同樣存在著一些缺點。除非你在測試中使用完全相同的內存數據庫,否則會不可避免的遇到兼容性問題。因為源數據的不同,很容易錯過正確的驅動操作的配置選項。最近我看到這樣的設置,在H2上配置使用了一個精確到毫秒的DATATIME column。在MySQL生產實例上使用同樣的模式定義,不僅需要DATATIME(3),還需要參數useFractinalSeconds=true。這個從H2遷移到MySQL實例上的問題直到測試后才被發現。
我強烈推薦測試盡可能在生產環境中進行。但是因為各種各樣的原因使它很難實現,比如在每臺開發平臺上安裝商業數據庫非常昂貴。有一個經典的方法可以繞過這個問題,就是可以給每個人提供單獨的開發數據庫。這就會導致一系列的問題,不僅僅是性能(因為總是被安裝在便宜老舊的硬件上)和測試重復性的問題。當兩個或兩個以上的人共享數據庫,然后同時運行測試時,可能會有不一樣的結果和不可預料的改變。隨著人數的增加,這樣的情況會更加嚴重。你會浪費很多時間重新運行測試,并試圖找出更加穩定的構建。
當你使用一個免費的MySQL數據庫或免費的NoSQL選項,在開發平臺中仍然會出現一些問題。例如,需要同時運行多個版本,或者需要通知他們需要構建怎樣的基礎設施和怎樣的接口。在這之前,我們還需要在培訓新員工上花費更多的時間。
值得慶幸的是近幾年出現了一些工具來幫助我們緩解這個問題,最顯著的有Vagrant和Docker。例如,Docker中的內置MySQL版本可以輕松的發出一下命令:
$ docker run -p 3306:3306 -e MYSQL_ROOT_PASSWORD=bob mysql
這將使用提供的根密碼,啟動一個最新的MySQL獨立版本映射到本地3306端口。我使用的四年前的蘋果筆記本,在最初的映像下載之后,只需要12秒的時間。如果你需要運行Redis 2.8,就在Docker上這樣寫:
$ docker run -p 6389:6389 redis:2.8
或者在不同的本地端口運行最新的Redis版本:
$ docker run -p 6390:6389 redis:latest
這將很容易的插入到你的構建系統中,使整個過程自動化。這就意味著開發者只需在本地機器上安裝Docker (或Vagrant)即可,并且可以將需要的基礎設施打包到腳本文件中。
當你的數據庫建立并運行起來后,這時你將面臨新的問題:我該怎么測試?根據實際情況的不同,測試方法也要相應改變。一個新建項目的初期階段我們會關心關系模式在怎樣迅速的變化。而一個既定的項目我們會更關注怎樣讀取現有的數據。 大多數情況使用Redis可以進行高速緩存,所以讀取現有數據會更容易些。(不是所有情況都可以,比如當Redis是主數據存儲器時。)
對于功能性測試,首先注意的是要使用干凈的空數據庫。測試的重復性很關鍵,一個空的數據庫可以確保這一過程的正確性。我通常會在測試開始的時候清除所有數據,而不是結束的時候。這樣在測試失敗的時候,可以方便查看數據來診斷問題。就以這樣的方式,重復你的測試就可以了。
目前流行使用一個叫DbUnit的工具,用來表達數據文件并可以輕松的加載測試數據。這時有兩個問題需要注意。第一,你使用的數據庫是否存在數據庫架構本身和測試數據之間的重復。因為無論是架構的改變,還是測試數據不再在測試類本身的改變,都會導致數據集文件的變化。可以參見示例3,DbUnit的XML文件。
另一個問題,新手常常會問驗證是否可以避開數據庫直接進行。數據回路測試(round-trip the data)是測試環節中一個重要的部分,因為你要確保你的數據可以被回讀。這個問題本質上是你在同時測試兩個項目,因此當出現故障時,你不能確定是哪里出了問題。如果你使用TDD(這是肯定的),那么問題就是運行與暫停之間的頻率不如以往高,不再需要以往那樣的快速反饋了。
這里我將這兩種測試方法結合起來,可以避免它們的缺點。第一個是我寫的一個純粹的讀寫測試,可以將數據手動輸入而比依賴測試本身。這樣的工作看起來重復繁瑣,寫入路徑還可能使測試代碼繞過一些邏輯關系。
例如,插入一個“ON重復鍵”(ON DUPLICATE KEY)就不必這樣做了。我們假設記錄不存在,測試的數據狀態完全可控。然后該測試將使用產品代碼回讀測試中插入和標記的內容,并且回讀的內容可以被驗證。請參見示例4的讀取測試。
一旦讀取路徑可用,寫入測試將使用生產代碼生成數據回路同時用來寫入和讀取。因為我們已經知道讀取路徑完好,所以只需要關心寫入路徑就可以了。當讀取路徑出現故障時也會導致寫入測試的失敗。但是當寫入路徑出現故障我們就可以找出問題的所在。此外,如果你使用DSL測試驗證讀取路徑,將會大大節省你的時間。請參見示例5的回路測試。
本站文章除注明轉載外,均為本站原創或翻譯。歡迎任何形式的轉載,但請務必注明出處、不得修改原文相關鏈接,如果存在內容上的異議請郵件反饋至chenjj@fc6vip.cn