看板 Soft_Job 關於我們 聯絡資訊
前情提要,這是寫給軟體開發者的測試歷程, 主要是以我自己進入測試的經驗說明如何進入測試門檻, 以及我身為軟體開發者進行軟體測試時需要知道的事情跟可能的心路歷程。 所有的內容都只是個人經驗僅供參考,歡迎提供意見分享跟挑戰。 ----------------------------------- 另外這裡所指的軟體測試都只是主要針對者自己對軟體的測試, 而與專案測試(目的為增加專案品質)的目的並不直接相關。 也就是說,這裡講的主要目的,是開發者如何可以在開發過程, 快速驗證自己的修改是否有誤跟常見的一些問題。 ----------------------------------- 本文開始 ----------------------------------- 我剛開始進入程式領域時, 並不會有組織化的架構,因為連邏輯都寫的很吃力。 測試時也會主要針對整個應用去做測試,(上一篇說過,這就是整合測試。) 因為整合測試實際上是以你寫完的作品去做實際測試, 所以在開發上是最直覺、最容易建立出測試流程的測試。 (但不見得是最容易測試的路徑) ----------------------------------- 最原始的整合測試的方法相當簡單,就是把程式整個執行, 然後按照始用者可能會操作的流程去測試預期的結果。 ----------------------------------- 之前提到當開始寫起複雜的應用程式之後, 測試其中一小片段的測試路徑,開始變得很高成本跟困難。 這時候測試路徑就會變得很複雜, 舉例,假設我寫了踩地雷好了, 我要測踩地雷標出所有地雷之後畫面顯示是不是對的, 難不成我每次修改那個畫面時,還要都去玩幾輪作測試。Orz ----------------------------------- 但是前面說過,這樣的狀況下,測試路徑實在是常到讓人厭煩。 於是我們會在整合測試的環境下,偷偷開始「作弊」, 以踩地雷為例, 我可能會 1.事先印出當局答案來加速測試 2.設定一些方式跳過遊戲內容直接進入遊戲獲勝 3.想辦法設計成可以對印出結果獨立呈現。 或者是我設計成使用者只要獲勝後,可以透過某個特定按鈕重新瀏覽勝利畫面, 我可以修改程式碼後,透過按鈕重新預覽 (像 java 的 hot-deploy )結果。 這些都相當倚賴於程式碼的實作,而你能夠越輕鬆(改越少code甚至不用改) 達到縮短測試路徑到能接受的程度,我稱之為越有「可測試性」。 ----------------------------------- 另外關於可測試性的還有其他的問題就是, 比方說今天這個測試環境需要資料庫的協助, 偏偏資料庫在遠方或者沒有測試用資料庫,測試時也會有狀況。 也就是環境相依性。 ----------------------------------- 可測試性可以用很多種方式呈現,我不想用 IOC 這種高級例子說明, 所以我們以第一篇中的停車場的例子說明好了。 main(){ //假設使用者輸入一行資料(停車幾分鐘)並轉數字 //並假設使用者都是善良user,不會輸入英數字 int k = console.getInt(); int hours = ceil(k/60) ; //除60並且無條件進位 int money = 50 * hours; print(money); } 這樣的範例,基本上他的可測試性會低於以下的程式碼。 ----------------- main(){ //假設使用者輸入一行資料(停車幾分鐘)並轉數字 //並假設使用者都是善良user,不會輸入英數字 int k = console.getInt(); print(countMoney(k)); } int countMoney(int minute){ //將計算封裝 int hours = ceil( minute/60) ; //除60並且無條件進位 int money = 50 * hours; return money; } ----------------- 理由是如果我今天要測試不同的 minute 的測資, 我只需要把 main 修改成這樣 main(){ print(countMoney(1)); print(countMoney(61)); print(countMoney(121)); } 相較於原本的版本而言,這樣的修改跟出錯的機率顯然小很多。 原本的作法我們可能會需要寫成 int inputs = [1,61,121]; for(int i = 0 ; i < inputs.length ; ++i ) int k = inputs[i]; int hours = ceil(k/60) ; //除60並且無條件進位 int money = 50 * hours; print(money); } 或者抽 method ,是不是看起來複雜跟改多了, 而且你可能需要直接動到你測試對象的程式碼。 這也是為什麼我們應該盡量將功能函式化降低耦合, 因為可以提供相對簡單的測試範圍。 模組化帶來的優勢,也有很大是在這一塊。 對於那些異動頻繁或者難以驗證的程式碼, 特別需要針對可測試性作結構上的加強。 而一旦你開始進行針對相對於整體的小單元去進行測試的過程, 基本上你就慢慢走離整合測試的路線,而開始往單元測試的路線前進。 基本上我是這樣一步一步往單元測試走, 如果不先了解什麼是可測試性跟慢慢在開發中累積驗證程式碼的經驗, 只想對著一整套的系統找出幾個勉強的區塊作單元測試根本是緣木求魚。 當我開始發現測資、測試路徑,並且開始觀察程式碼的可測試性, 我自然會發現那些重要的核心程式碼,因為他們太常需要被測試, 而已經慢慢的以某些形式, 被轉化成比其他部份的程式碼更有可測試性的版本。 我們接下來一篇會繼續談到,我們眼前這樣修改程式碼的測試, 所累積下來的經驗,跟他有什麼缺點。 -- ※ 發信站: 批踢踢實業坊(ptt.cc) ◆ From: 223.143.225.151 ※ 編輯: TonyQ 來自: 223.143.225.151 (03/25 21:28)
samsonjr:推,淺而易懂卻又讓新人值得思考的經驗知識分享qq 03/25 23:14
※ 編輯: TonyQ 來自: 220.133.44.37 (03/26 14:19)
TonyQ:web版網址 http://disp.cc/b/575-3nbE 03/27 12:50
ggg12345:測試的難易度跟是否具可量測性?似乎沒有先釐清可以->難易 03/28 01:05
ggg12345:有輸入無輸出根本無從測起,不必輸入就有輸出是試不出變化 03/28 01:10
TonyQ:的確有些東西是無法測試的,至於難易度的量測,我覺得取決於 03/28 01:13
TonyQ:經驗居多。 03/28 01:13
ggg12345:具備輸入與輸出才能談試與測,有目的的測試就有涵蓋與難易 03/28 01:16
TonyQ:當然,這部份跟 yoco 提到的 pure function 是一樣的概念 03/28 01:23
TonyQ:越能夠以清楚的 input 跟 output 表達的就越容易測試 03/28 01:23
ggg12345:testability of code是指是否可快速有效又全面性測出正誤 03/28 01:24
TonyQ:至於難易,目前主要的困難還是在測試對象(輸出)的明確跟輸 03/28 01:24
TonyQ:入的資料準備。 03/28 01:24
TonyQ:「全面性」?我不覺得測試 code 有所謂全面性可言,那取決於 03/28 01:25
TonyQ:你對測資的掌握程度,而我認為它是個99% 以下的東西,永遠有 03/28 01:25
TonyQ:1% 是你無法掌握的意外。 03/28 01:25
TonyQ:我寧可說,那是個「可靠度」。 03/28 01:26
ggg12345:程式的對錯(或特性)是可以証明或推定的,當然是假設執行的 03/28 01:35
ggg12345:載體是照理想做事的.但載體有其極限(如位元數),因此有適 03/28 01:38
ggg12345:用範圍.通常測試是為了驗證合乎需求?有限的需求就可測試! 03/28 01:44
ggg12345:容易或不容易快速測定正誤是被追求的,寫的想要驗的也想要 03/28 01:50
ggg12345:實體的機器會有難達理想狀況的意外,做為數理邏輯的code是 03/28 01:57
ggg12345:依照特定的功能性運作,若不違反可測性就能被全面性論定. 03/28 02:02
ggg12345:不過,要做得涵蓋面夠齊全,又快速測定那就會有難易問題了! 03/28 02:08
TonyQ:有限也要時間允許啊,NP 問題也很有一些是有限解但解不完的 03/28 11:11