為什麼要給軟體做測試?如何測試呢?
你為什麼應該測試你的軟體?你應該如何測試軟體?有些人對這些問題有非常簡單的回答。
及時享樂型的程式設計師根本懶得去測試,快樂地活在當下。更嚴肅的程式設計師會告訴你軟體測試是為了開發出高質量的產品。為了可以開發出高質量的產品,必須始終編寫單元測試和整合測試,並做 QA 測試。忽略這些,你的程式碼將會掉入 bug 為患的深淵。
儘管我更贊同第二種觀點,但我認為這不是一個完美的答案。考慮到不同的軟體專案的差異,一套答案似乎不可能適合每個人。
- 移動遊戲、醫療裝置和線上商店三者各不相同。
- 每個組織也不盡同的,初創公司和大型跨國企業所擁有的資源是無法相提並論的,和 NASA 也是完全不一樣的。
- 每個專案都會經歷不同的階段,沒有使用者的產品和有成千上萬交易的產品有非常不同的地位
你需要的不僅僅是一個答案,而是如何去選擇適合你情況和需要的答案。我們首先會考慮適合你的測試方法。然後我們會考慮為什麼要測試你的軟體。最後,我們將結合方法和目標,來看一下你可以選擇什麼方式去測試你的軟體。
你可以用什麼樣的測試方法?
首先,我們考慮下可以使用的不同測試方法。下面的程式碼是測試嗎?
12 | def test_add():assertadd(2,2)==5 |
我會說,是的,那就是一個測試。從函式名上可以看出來。這個測試證明了函式add() 做了什麼:對兩個數字做加法,然後將結果返回給我們。
你一定注意到了,這個測試是錯誤的。幸運的是,我們的開發過程有另一步驟:程式碼審查。親愛的讀者,你可以作為一個程式碼審查者並告訴我,我的程式碼是錯誤的,2加2是4,不是5。
程式碼審查是一種測試方法嗎?如果你試圖驗證你的程式碼符合規範,那麼這就是一種測試。你大腦中有算術規範(”2 + 2 = 4″),你就會檢查你的程式碼是否符合這個規範。
讓我們把程式碼審查和自動化單元測試都做分別作為一種測試方法。儘管他們都是測試,他們也非常不同。他們之間的主要區別是什麼?
測試的一種方法是自動化的,另一種是由人類完成的。
自動化測試是連續的和可重複的,你可以這麼寫:
123 | def test_add_twice():foriinrange(10000000):assertadd(i,i)==2*i |
計算機將會每次執行完全相同的程式碼,該程式碼將會確保函式 add() 對於這些特定的輸入返回特定的輸出。人在手動驗證一千萬種不同的計算時會遇到一些困難:無聊、分心、錯誤、遲緩。
另一方面,人類在閱讀這個程式碼時,會告訴你這是bug:
12 | def add(a,b):returna+b+1 |
計算機所做的事情,無論是好是壞,人類都能明白他的意義。只有人類才知道軟體的意義是什麼。
現在我們可以按照使用的方法來對測試進行分類:人類測試意義,自動化測試確保一致性。
你為什麼要測試軟體?
接下來,讓我們考慮測試目標。
測試軟體的第一個可能的目標就是確保它符合規範。這個目標是大多數程式設計師在討論測試時想到的:它涵蓋了單元測試和手工測試,它也包括程式碼審查。你的軟體具有某些必須的功能、規範,你想確保它在現在和未來也確實是這樣的。
一些需求是高層次的:一個線上商店想要顧客可以訂購他們新增到購物車的產品。其他需求是低層次的實現細節,只有程式設計師感興趣。你可能想要函式 verify_creditcard() 接收信用卡號碼作為字串,然後如果信用卡是無效的,丟擲一個 InvalidCreditCard 異常。
所有的這些需求都是規範,他可以被寫的非常詳細,也可以是頭腦中的一個概念(如 2 + 2 等於 4 )。無論如何,你測試你的軟體是為了確保它做了它應該做的事。
然而,有時測試也可以有不同的目標。在 Eric Ries 的書《精益創業》中, 他提到編寫軟體後卻發現沒有人真正想用它的問題。如果沒有人使用你的軟體,花費了大量的時間去測試,確保你的軟體滿足規範就是浪費時間。
Ries 認為你首先應該搞清楚一個產品是否會成功,通過測試他稱為的“最低可行產品”是否擁有潛在的使用者和客戶。這是一個與眾不同的測試形式:它不是驗證你的軟體是否滿足規範,而是學習你以前不知道的東西。
軟體測試第二個可能的目標就是為了獲得知識。讓我隨著這個目標看一下另一種測試形式。“A/B測試”就是你使用兩個變數,然後看哪個變數產生更好的結果。或許你正在測試重新設計的網站:你給 90% 的訪客展現你目前的設計,10% 的訪客展現你的新設計,然後看哪種會讓你的產品有更多的使用者註冊。
注意,你有兩套規範,並且已經實現了他們。測試的要點就是找到哪種規範更好,學習一些新的東西,而不是驗證實現是否符合規範。
現在我們已經知道為什麼你需要做測試:要麼驗證你的實現符合規範,要麼獲得新的知識。
你應該如何測試軟體?
結合我們提出的那兩個目標(獲得新知識和滿足規範)和兩種測試方法(手工測試和自動化測試),你會得到四種不同的測試形式,每種都會有更詳細的測試目標。
對於你特定的需求和情況,你必須選擇一種合適的測試方式。讓我們逐個介紹這四種測試型別,看看每種測試型別應該在什麼情況下使用。
理解使用者
- 使用者會購買你的產品嗎?
- 一個設計的改變會帶來有更多的註冊嗎?
- 使用者會理解你的軟體是如何工作的嗎?
這些問題都無法通過對比你的軟體是否滿足規範來得到回答。相反,你需要經驗知識:你需要觀察當你的軟體展現給使用者時,使用者真正做了什麼操作。
相關的測試技術包括:
- 可用性測試
- 最低可行產品測試(《精益創業》)
- A/B測試
理解執行時行為
- 你的軟體在負載下的表現如何?
- 你的軟體有資源競爭嗎?
- 當有非法輸入時,你的軟體是否會崩潰?
這些問題不能總是通過比較你的軟體是否符合規範來回答。一旦你的軟體足夠複雜,你無法完全理解或者預測它的迴應。你需要觀察它的實際執行來理解其行為。
相關的測試技術包括:
- 壓力測試和浸泡測試
- 從產品日誌中收集異常及跟蹤資訊
功能的正確性
- 你的軟體是否真正符合規範?
- 你的軟體是否做了它應該做的事?
很容易可以看到,自動化測試可以證明這些,但是請記住檢查2+2等於5的單元測試。在更基本的層面上,軟體可以在技術上滿足規範,但是不能達到規範的目標。只有我們理解規範背後的含義,然後才能確定軟體是否達到了目標。
相關的測試技術包括:
- 手動使用者介面測試(如:QA人員使用您的網站)
- 程式碼審查
功能的穩定性
- 對於同樣的輸入,你的公開介面(API)是否總能返回相同的結果?
- 你的程式碼是否提供了它應該提供的保證?
人類很不擅長測試這些情況。人類非常容易忽略小的變化:如果一個按鈕從“Send Now”改變為“Send now”,你可能根本就不會注意到。相反,如果你的介面從sendNow() 變為 send_now(),或者返回值的型別有輕微變化,你的軟體就會崩潰。
這意味著一個公開介面,尤其是其他軟體依賴的介面,為了保證正確性必須要穩定。當你不斷更新你的測試時,為改變頻繁的私有介面或者程式碼編寫自動化測試,將會導致非常高的維護成本
相關的測試技術包括:
- 單元測試、整合測試和其他類似的自動化介面測試
- 自動化使用者介面測試(如:網站的Selenium測試)
- 編譯器檢查和靜態檢查
模型的應用
那麼這一切有什麼好處呢?
選擇如何去測試
首先,我們最初的目標:基於你的目標,這個模型可以幫助選擇測試形式。
考慮一個新建立的產品,不確定什麼樣的人願意使用這個產品。自動化測試的重點在於確保程式碼符合規範,因此在搞清楚使用者真正的需求之前,編寫自動化測試用例可能是浪費時間。
精益創業(Lean Startup)是一種可行的替代方法,它的目標是找到什麼樣的產品可以滿足使用者的需求,它側重於實驗或者嘗試。這意味著專注理解使用者這個象限。一旦選定了產品,你就可以花費時間在確認“最低可行性”之外的地方,比如投入更多的資源保證軟體功能的正確性和穩定性。
辨別你是否選擇了錯誤的測試型別
第二,當你選擇了錯誤的測試型別時,這個模型可以幫你改變航向。比如假設編寫稅收軟體(細節源自一個真實案例),他們為他們的web介面編寫了Selenium測試,與此同時他們的web介面做了重大的改變。
即使做了測試,他們的程式依然是有bug的,每次改變介面這些測試用例就不能使用了。測試似乎沒有提升質量,但是它浪費了開發者的時間進行維護。他們做錯了什麼?
這個問題就是他們的系統實際上有兩部分:
- 稅收引擎相當穩定,稅法每年只改變一次。對於使用者來說稅收引擎中的錯誤是一個主要問題,對於開發者來說不相容的介面改變是一個問題。這表明需要穩定的功能測試,比如針對稅收計算引擎的單元測試。正確的功能可以通過程式碼審和查稅務會計的反饋來保證。
- 基於web的使用者介面。UI介面頻繁的變更,這表明穩定的功能測試現在還不是目標。現在的目標是功能的正確性,所以UI介面應該進行手工測試(比如:當程式設計師寫程式碼時進行測試)
討論測試的基礎
最後,這個模型提供了一個共享的術語,這個術語可以幫助你在廣泛的意義和不同的目標下討論測試。
- 可以不必再對手工測試和單元測試哪個更好進行無休止的爭論,從這個模型中可以非常清楚的展示出他們之間的差異。
- 你還可以與公司的其他部門(如市場營銷)討論測試,這會是一個非常不同的測試視角。
總結
你為什麼要測試你的軟體?要麼獲得知識,要麼滿足規範。
你測試軟體的方法有哪些?手工測試或者自動化測試。
你應該如何測試你的軟體?根據你特定的情況,選擇相關的測試形式,如理解使用者、理解執行時行為、功能的穩定性、功能的一致性。
打賞支援我翻譯更多好文章,謝謝!
打賞譯者
打賞支援我翻譯更多好文章,謝謝!
任選一種支付方式