熱線電話:13121318867

登錄
首頁精彩閱讀永遠不要忘記數據庫測試 數據庫測試的重要性和測試要點說明
永遠不要忘記數據庫測試 數據庫測試的重要性和測試要點說明
2014-12-21
收藏

永遠不要忘記數據庫測試 數據庫測試的重要性和測試要點說明


譯者導讀:本文分為三部分,第一部分是第1節,即說明“對數據庫測試的根本誤解”;第二部分從第2節至倒數第4節,詳述“數據庫測試測什么”的問題;第三部分是最后3節,引出“數據庫測試怎么測”的問題,提出自動部署、自動化測試、持續集成的思路及工具。另,副標題是俺自行添上去的,以明示本文意圖。

對數據庫測試的根本誤解

有許多關于測試驅動開發(Test-Driven Development,縮寫為TDD)的書籍。那些書通常關注的是將測試應用于工作單元(units of work)。對于工作單元的理解有許多種不同的方式,通常它表示一個類(class)。正如那些書中所言:編寫許多測試,以使那些測試都能通過的方式創建代碼。應模擬所有的外部資源,以便你可以只測試這個單元。

這很酷,但不幸的是所有的測試在此刻停止了。因為通常會有些沒被測到的查詢(手寫的或者是由某些ORM工具生成的)。有些程序員使用集成測試來測試那些查詢——連接到一個真實的數據庫并執行真實的查詢來進行測試。這種做法通常意味著在測試快樂路徑(happy path)——我已經有了ORM工具,所以它會搞定每件事,我無須費心。

數據庫通常是一家公司最有價值的資產。應用程序可以一遍一遍重寫。舊的應用程序扔出去,新的應用程序裝進來。但是更換應用程序時沒人會丟棄滿載數據的數據庫。而是將數據庫小心翼翼地遷移過去。位于多個系統中的許多不同的應用程序會在同一時刻使用同一數據庫。這就是為什么擁有充滿約束的良好數據庫模型是如此重要、以及為什么應謹慎對待數據庫的原因。你真的不想破壞數據一致性(consistency),因為這會使你的公司付出高昂的代價。

本文是關于經常被遺忘的數據庫測試的。使用真實數據進行集成測試。實際上,它與你所使用的數據庫引擎的類型無關緊要。你可以使用PostgreSQL、MySQL、Oracle,或者甚至使用那些有趣的noSQL數據庫,例如MongoDB。以下規則可適用于各種數據庫和各類應用程序。也許不是全部,例如noSQL數據庫就無法強制實施數據完整性(integrity)。

你的應用程序通常是由許多不同的部件組成的。其中有一些<將任何你喜歡的語言放在這里>代碼,一些配置文件,一些SQL查詢,一些外部系統。測試一個應用程序意味著分別測試每個部件(因為只有這樣才更容易找出bug)、以及測試所有部件是如何協作的。數據庫就是這些部件的其中之一,而且你應該徹底測試它。

不測試數據庫

這是首要的、最可怕的錯誤。根本不測試數據庫。你編寫了一些使用數據庫的代碼。你甚至使用一些模擬數據庫連接為這些類創建了單元測試。

集成測試怎么樣?集成測試應在生產環境下對應用程序進行測試。集成測試背后的唯一想法是,確保應用程序部署到生產環境后可以正常工作。如果你不在生產數據庫上測試應用程序,那么你實際上不并不知道應用程序能否工作。你的模擬連接讓你可以發送尚未檢查以及沒有檢查的任何查詢。模擬連接只返回你所需的數據。

不創建集成測試意味著你實際上沒有測試你的應用程序。

不測試數據庫Schema(模式/架構)

我所觀察過的大多數團隊擁有某種形式的集成測試。通常進行快樂路徑測試:有某個ORM工具,我們持久化對象,ORM工具會完成那些工作,真是太酷了,我無須費心。

我從未見過一支對數據庫schema(模式/架構)進行測試的團隊。想象一下,由于某些針對產品的查詢很慢,因此你必須在該數據庫中創建某個索引。當下次在新的客戶環境中部署此應用程序時,你希望擁有該索引并確認該索引真的就在那里。為什么不編寫一個簡單的測試來檢查該索引的存在呢?

除了索引,還有許多要測試的內容:

  • 主鍵(primary keys)
  • 外鍵(foreign keys)
  • 一些檢查——以確?!皃rice”(價格)列不會有負值
  • 某些列的唯一性(uniqueness)——你實際上不想擁有兩個具有相同登錄名的用戶。

不在生產環境下測試

當你開發某個應用程序時,你可以從種類繁多的數據庫中進行選擇。通常你會從中選擇那個最好的、那個被團隊所熟知的、或者是由管理層所選定的(有時使用一些奇怪的理由)。有時同一應用程序的多個部署會在同一時間使用不同的數據庫引擎。有時應用程序會為了能使用不同的數據庫引擎進行準備,因此購買此應用程序的客戶就可以選擇他想要的數據庫。

數據庫引擎的選擇真的與進行產品測試無關。

由于程序員的懶惰,因此他們希望他們的測試可以運行得飛快。他們不想為測試結果等太久。這也就是為什么許多團隊使用某些更快的內存數據庫(例如HSQLDB)的原因。由于那些內存數據庫僅存儲在RAM(Random Access Memory,隨機存取存儲器)內存中,而且在操作時不接觸任何硬盤驅動器,因此它們的運行速度要快得多。

還有一條常常被人遺忘的規則:

測試應該使用與生產環境相同的數據庫引擎。

許多程序員會使用某個其他引擎。常見的解釋很簡單:“我們的數據庫太慢了,我們應該使用某個內存數據庫引擎?!?。這并不是個好主意。這樣你測試的是該其他引擎,而非你的生產環境中的那個,所以實際上你并沒對你的應用程序進行測試。

我曾經遇到過這個問題。我們必須在成功連接數據庫后通過設置session變量來優化查詢。那個應用程序在生產環境中只使用Oracle數據庫。當設置此變量以后,測試失敗了。而且是所有的測試都失敗了。原來是我不能在HSQLDB內存數據庫中設置此變量,因為它根本不存在。因此,我必須編寫一段糟糕的代碼:在連接后,檢查數據庫引擎,并由此決定是否設置此變量。

即使你沒有任何與混合引擎有關的問題,請記住,當你測試其他非生產環境的數據庫引擎時,你恰恰根本沒對你的應用程序進行測試。

不準備好數據庫就進行測試

測試有一個通用的、明確定義的流程。 它非常簡單:

  • 準備環境
  • 運行一個測試
  • 檢查測試結果
  • 返回至第一點

若嘗試背道而馳,則你會被它所傷。

你察覺在測試之后是沒有整理(tidying)的么?

這點非常重要:必須在測試前準備環境,而非測試之后。你無法確保測試將能夠清理一切。應用程序可能因為某個錯誤、網絡連接失敗而退出,或者應用程序可能崩潰(例如,由于內存不足異常)。該測試如何終止并不重要,真正重要的是該測試運行在為每個測試所準備的相同環境中。

我曾犯過這個錯誤:有大量的集成測試,它們會在每次測試后清理所有更改。許多程序員正使用調試器來運行這些測試,并且當發現bug后會在中間停止測試。任何在該測試之后運行的測試會得到不可預知的且隨機的結果。因為它正運行在已被前一測試所改變的環境中,而且沒有為其清理整個環境。

準備了數據庫卻不對其檢查就進行測試

在前面的部分中我提到許多有關準備數據庫的內容。我還想補充一點。準備數據庫是不夠的。當你通過清理某些表、加載配件等等準備好數據庫時……還剩下一件事情要做。

在準備完畢后,要檢查數據庫狀態。

你真正需要確保的是你已將一切準備妥當。當出現由于bug所導致的某些數據留下來且未能清理時,這些工作就可以節省你的時間。

這應該是測試前數據庫準備的一部分。

不測試創建腳本

每個應用程序都需要某種形式的安裝過程。而對于你部署數據庫而言,永遠是第一次。

程序員往往會通過手工執行某些臨時的數據定義語言(DDL,data definition language)查詢來改變數據庫。他們稍后并沒有把那些語句寫下來,或是忘記了所做的改動。他們沒有更新安裝腳本。大多數團隊不使用有版本控制的腳本(例如,Ruby on Rails中的Migrations、或者是Java世界中的Liquibase)。

對測試而言最好的方式是,在運行測試套件前重新創建數據庫。你不必在每個測試開始前都那么做。只在運行所有測試前運行一次就行了。

是的,寧可事先謹慎有余,不要事后追悔莫及。

不測試外鍵

外鍵是提供數據庫一致性的基本途徑之一。在良好的關系數據庫schema中,你應該擁有各種鍵。如果你沒有的話,那么這可能表明你有一個真正的大問題。然而,這取決于數據模型,但是通常缺乏外鍵是種非常糟糕設計的味道。

測試外鍵很簡單。只需在事先沒有在引用表中添加適當的行的情況下,為某個表添加一些行。你應該得到一個錯誤。然后,你應該從引用表中刪除行,你可能得到錯誤,或沒有錯誤(這取決于該鍵的定義)。無論如何,你都應該檢查一下預期行為。

不測試默認值

在良好的數據庫設計中,你應該定義一些合理的默認值。通常這些默認值可能是空(null)。即便這些空也應該進行測試。你不能假設,只有你的應用程序將改變此數據庫中的數據。\ 兩個問題:

  • 如果某人想創建一個快速修復并使用臨時SQL查詢更新某些數據,該怎么辦?
  • 如果有一天某人啟動另一應用程序,它可以改變這些數據,而且新的應用程序將不使用你的ORM映射或你的DAO(數據訪問對象)類,又該怎么辦?
  • 如果你擁有愚蠢的默認值、或是錯誤的默認值,那么你可能會破會數據,而且那可能比一個簡單的應用程序bug更糟糕。

不測試約束

在數據庫中還有更多約束,不僅只有主鍵和外鍵約束。你可能擁有一些唯一的(unique)或不為空的列。你可能約束某列只有很少的值集。你可能想確保價格永遠不會低于0。

良好的數據庫schema應擁有許多約束。你也應該測試它們。如果你希望你的價格列只能擁有正值,當你嘗試向其中插入-1美元時會發生些什么?為什么不測試一下呢?

你不能假設只有你的經過良好測試的應用程序將使用那些數據,而且這些檢查是為你防御這些bug的最后一道防線。為什么不測試它是否正常工作?

多個測試可以更改同一數據庫

通常,數據庫測試會更改數據庫。你可能同時運行多個測試,但是你必須確保那些測試彼此之間沒有影響。你必須確保,如果某個測試將一些內容寫入數據庫,而另一測試將不會讀到。

通常,很容易搞得一塌糊涂,因此我小小的忠告是:避免在同一時間運行多個測試。這也意味著,你不應該在多臺機器運行相同的測試套件。

當你有許多想運行測試的開發者時,他們每個人應該擁有可用于編寫測試的單獨的數據庫。如果你擁有某種形式的只讀數據庫,沒關系,多臺機器可以在同一時間使用這個數據庫。但是如果你允許所有程序員使用同一數據庫進行測試的情形出現,那么你可能真的會得到不可預知的測試結果。

當程序員在某個測試中發現一個錯誤時會怎么做?那么,優秀的程序員會盡量修正錯誤。如果該測試失敗僅僅是因為另一程序員在同一個數據庫上運行他的測試所導致的話,那么修正此類錯誤只是在浪費程序員的時間。

沒有大紅按鈕

優秀的程序員是懶惰的。如果你命令優秀的程序員每次都重復同樣的任務,他們會越來越沮喪。優秀的程序員會自動化可重復的事情。

在每個項目中,你必須在測試環境中部署某些東西。做這些會花去多少時間?你真的想為了重新部署應用程序和加載數據庫一直浪費你的程序員時間么?

這就是為什么每個項目都應該有個大紅按鈕的原因。某位程序員可以按下此按鈕,然后沖杯咖啡,回去工作,并且幾分鐘后得知的大紅色按鈕完成的工作,一切準備就緒。

大紅按鈕真的會為你節省很多時間。你會說自動化所有工作實在太緩慢。然而,事實并非如此。恰恰相反,就像說測試驅動開發(TDD,Test-Driven Development)很慢一樣。在最初的時候比較慢,但隨著項目變得更加復雜,由于存在測試或按鈕,會為你節省更多的時間。各種各樣的大紅按鈕——你可以用它們部署應用程序、運行測試,以及類似的后方支援。

有時會使用Jenkins(又名Hudson)來做這些。是的,對于此類大紅按鈕而言這是一款偉大的軟件。唯一的事情是,每位程序員應該有其自己的一組工作以便在其自己的環境中部署所有的內容,在其自己的環境中他(或她,當然)可以自由發揮,而不會影響他人,同樣也不會受到他人的影響。

工具

有許多數據庫測試工具。為了測試整個schema,你可以編寫簡單的集成測試。對于PostgreSQL有pgTAP,使用TAP插件它可以與Jenkins集成到一起,因此Jenkins可以擁有一項用于測試數據庫(包括生產數據庫)是否正常的工作。

SQL

數據分析咨詢請掃描二維碼

若不方便掃碼,搜微信號:CDAshujufenxi

數據分析師資訊
更多

OK
客服在線
立即咨詢
日韩人妻系列无码专区视频,先锋高清无码,无码免费视欧非,国精产品一区一区三区无码
客服在線
立即咨詢