※ 本文為 TonyQ 轉寄自 ptt.cc 更新時間: 2012-05-27 18:10:27
看板 Soft_Job
作者 標題 [閒聊] 笑談軟體測試的幾個階段(四)
時間 Mon Mar 26 01:41:21 2012
前情提要,這是寫給軟體開發者的測試歷程,
主要是以我自己進入測試的經驗說明如何進入測試門檻,
以及我身為軟體開發者進行軟體測試時需要知道的事情跟可能的心路歷程。
所有的內容都只是個人經驗僅供參考,歡迎提供意見分享跟挑戰。
-----------------------------------
另外這裡所指的軟體測試都只是主要針對者自己對軟體的測試,
而與專案測試(目的為增加專案品質)的目的並不直接相關。
也就是說,這裡講的主要目的,是開發者如何可以在開發過程,
快速驗證自己的修改是否有誤跟常見的一些問題。
-----------------------------------
本文開始
-----------------------------------
上一篇我們談到程式碼的可測試性,然後你會發現,
我們這系列到現在還沒談到 unit test 的 test case 要怎麼寫,
也沒有講到什麼神奇的自動化測試,更沒有提到測試可以幫你什麼。
我只說了,
1.測資:你要知道要測什麼,不然也沒什麼好測的
2.測試路徑:你要知道你現在測試要怎麼測試
3.可測試性:你的程式碼經得起測試嗎?
-----------------------------------
為什麼?
-----------------------------------
答案很簡單: There's no magic.
單論測試而言,你我等每個會寫 code 的開發者,
可能都會從軟體開發過程中累積無數次,成千上百甚至上萬次的測試經驗。
如果看也不看這些測試經驗一眼,那他們也不過就只是虛度的光陰,
這些經驗需要被組織,被思考,被強化,
所有的測試方法論大抵上我認為都不出這個環節。
所以不談開發方法,不談進入開發過程我們會碰到的事情,
要怎麼單刀切入測試呢?
即使我有個寫測試很快的工具,但我想不到測資也只是完蛋,
當然這些工具會有其神奇的地方,但是在那之前我們還有事情要知道。
所有的工具都是試圖幫你簡化流程,
但是這些工具簡化了哪些流程,便是我正試圖說明的事情。
-----------------------------------
這一篇我們要繼續舉實例說明可測試性的幾個樣貌,
然後開始批判這樣作的缺點。
-----------------------------------
先舉低可測試性的案例,
以前我專案中有個設計是跟其他網站合作,使用他們 avatar 的共享服務。
也就使用者在我這邊上傳使用者圖片,
我需要使用合作夥伴的 api 更新他們的 avatar 資料,
因為對方服務不太穩,所以我也在使用者登入時去 sync avatar ,
把圖片存在自己家跟自己顯示避免對方服務掛掉害到我自己。
因為加入額外的操作,所以我登入跟上傳圖片時,
要考慮的事情變多了,我甚至要連我登入緩慢時,
要考慮的事情變多了,我甚至要連我登入緩慢時,
是不是對方網站速度變慢,導致擋到我的路都要考慮進去。
-----------------------------------
考慮到可測試性,這樣的程式碼是不行的,
所以後來改採用背景處理之類的方案,
使用者上傳跟登入都只是在 db 註計狀態,由獨立程式去進行動作。
如果獨立程式有 exception ,那就表示是對方服務出包,
我也不用在我的測試週期中擔心他。
這類的事情也常發生在「寄 email 」上,
因為 smtp 一樣是有可能會噴 exception 的服務,
我後來習慣上也都是採取一樣的作法開一張 mail table 去操作。
-----------------------------------
再來其他測試性的案例, 7-8 年前 ORM 跟資料庫工具還沒這麼流行時,
開 db connection 一堆 sample 都是要用時寫 ip account/password。
Sample 不會教你什麼模組化...
開 db 寫個表格什麼的都在對應程式碼裡面寫一次帳密,
新手傻傻的照著寫就會發現換個測試用 db 就整死自己。
新手傻傻的照著寫就會發現換個測試用 db 就整死自己。
解法就是把這些包起來,做出 Connection 類別,統一管理。
在一條測試路徑上,需要修改的重複代碼太多,也會降低可測試性。
-----------------------------------
以上我們說的,都還是「開發過程」中帶來的測試困擾,
而不是「為了寫測試」而發現的測試困擾。
這系列的文章設定是即使你不寫 unit test ,不搞自動化測試,
只有手動化測試它還是該要對你有幫助。
然後你可能會發現,這些事情也就是開發者所謂的「程式好不好寫」,
本來就寫程式而言,測試跟開發就是密不可分的,
因為你總要驗證你寫的 code 是不是會動。
(註:是不是所有情境會動是另一回事,但總有一個情境要會動吧。)
-----------------------------------
前面的可測試性可能有點抽象,我們繼續談些可測試性的案例,
@相依過多的「狀態」會導致可測試性下降,
通常相依一個狀態就會有一層條件式判斷,而且每多一個就會讓複雜度上升。
舉個例子,假設你今天論壇網站有做網站分級制度,
你設定登入兩百次、發文兩百次以上的是黃金會員,
你設定登入兩百次、發文兩百次以上的是黃金會員,
登入一百次、發文一百次以上的的是銀會員,其他的是一般會員。
(為解說方便,假設會員等級永遠就只有這三種。)
假設會員是 user 好了,比起在程式碼中判斷
if( user.getPosts() > 200 && user.getLogins() > 200 ){ //gold
//作黃金會員該做的事情
}else if(user.getPosts() > 100 && user.getLogins() > 100){ //silver
//作銀會員該做的事情
}else{ //normal
//作一般會員該做的事情
}
你會發現,雖然你是要測試黃金會員跟銀會員的執行路徑,
但是你測試時卻需要發文數(posts) 跟登入數( logins ) 的資訊。
如果我今天程式碼是這樣,我可以更針對我想測試的目標去測試,
我也不見得要煩惱說 posts 跟 logins 是不是對的,
if(user.isGold()){
}else if(user.isSilver()){
}else{ //normal
}
以 Java 而言,要測 Gold user,
可以讓測資複寫 User 讓 isGold 回傳 true,就不需多知道文章數等資訊,
至於文章數判斷,那可以切給另一個地方測試。
更不用煩惱我今天萬一改了 posts 跟 logins 的條件,
要怎麼讓系統中的資料一致。
當然也可能會考慮視情況選用策略模式甚至是狀態模式,
我要強調的是測試對象狀態如果可以減少,測試性會提高。
不過因為增加函式也有增加函式的維護成本,
所以事實上你該怎麼作,還是因時地而異。
這裡只是再次說明,程式的架構會大幅影響可測試性。
(有沒有很熟悉,其實我們還是在談模組化程式開發。)
-----------------------------------
接下來我們談測試經驗管理
-----------------------------------
到這裡我們談論的都還是直接改 code 測試,
一般而言,因為改 code 測試不太方便保存,
一般而言,因為改 code 測試不太方便保存,
有一種作法是把測試碼註解,需要的時候在把註解拿掉回來測試,
但是會讓程式變得有點肥。:x
如果以 Java 來講,
也有人會對 util class 寫 main method 放測試 code ,
反正平常不會有人無聊去執行非主要的 main method 。
或者是給一個特定系統變數,如 debug = true ,滿足時就跑特定測試 code。
有點像 Java 的 system properties 、
有點像 Java 的 system properties 、
php 的 if(isset($_GLOBAL["debug"])) 或諸如此類的東西。
-----------------------------------
測試案例保存的好,
以後要測試可以事倍功半,是目前至今有討論過的測試案例,
幾乎都要異動現有程式碼把測試程式加進去,所以要談談這樣作法的許多缺點。
這樣當然顯然是有缺點的:
1.如果沒有保存測試案例
你每次做完測試之後就只有那次有用,下次就要再重來一次了,
基本上你只有在不斷練打字跟溫習系統,有蠻多時間在「回想」。
2.如果你在註解保存測試案例
你程式碼環境引入複雜的測試資訊,而你程式碼總是會改的,
你無法保證你的測試碼一定跟的上。
再者,因為註解通常不視為程式內容,
你無法善用 IDE 或語言除錯工具給你的幫助,
如果類別改名字之類的,維護上會很麻煩,
常常你移除註解還要修 test case 才會動。
常常你移除註解還要修 test case 才會動。
3.如果你利用特別 method (ex. java 的 main) 或 flag 保存測試案例
a.機制可能會太複雜、麻煩。
(main 應該是還好,但是萬一碰到真的有 main 的 class 你就沒得測了)
b.插 flag 的要擔心效能問題,另外通常都一個參數對應所有程式,
b.插 flag 的要擔心效能問題,另外通常都一個參數對應所有程式,
要怎麼只針對想測試的去設定,不要因為這樣跑出太多無關的訊息,
這還蠻麻煩的。
不是插一群的,會像是 java 的 logger 的這種工具
雖然可以針對特定類別設定 log level 跟判斷,
但是設定檔真的是很龜毛。-_-
c.可能會影響到 production 。
這是最糟糕的,一個不小心 ,
test case 就可能變 bug 或使用者可以鑽的漏洞了。
所以我們通常都不會太想把測試保存在專案裡面,
那期待中最理想的方法是什麼?
1.放在測試專屬的資料夾或 package 底下,
並且正式 production 必須不引入測試,也要這樣還能運作。
2.開啟獨立的測試專案來放這些測試碼
3.讓測試簡單到不需要保存
但根據目前我們提到的測試情境,我們只是寫了一堆邏輯,
並且試著在整合測試的環境,藉由修改程式碼來達到每次修 bug 的測試,
所以我們現在事實上還沒有能力作到把測試獨立出來。
光是要滿足整合測試的所有條件你大概就等於自己重寫一份了,
到時候大概你反而要測試你的測試案例。(大笑)
我們會將在之後的章節繼續介紹怎麼繼續往下走得路。
--
因為現在有點想睡,寫的可能比較複雜些,
有論述不清的地方可以再推文討論。:)
--
※ 發信站: 批踢踢實業坊(ptt.cc)
◆ From: 223.143.225.151
※ 編輯: TonyQ 來自: 223.143.225.151 (03/26 01:42)
※ 編輯: TonyQ 來自: 223.143.225.151 (03/26 01:44)
※ 編輯: TonyQ 來自: 223.143.225.151 (03/26 01:45)
※ 編輯: TonyQ 來自: 223.143.225.151 (03/26 01:49)
推 :這系列的文章 好!!!!!!!!1F 03/26 21:32
--
回列表(←)
分享