※ 本文為 cuteman0725 轉寄自 ptt.cc 更新時間: 2013-12-04 00:17:14
看板 Soft_Job
作者 標題 [心得] 軟體可測試性
時間 Tue May 29 22:43:55 2012
影響Test Case ROI的另外一項重要因素,是軟體可測試性(Software Testability)
Ref:
http://en.wikipedia.org/wiki/Software_testability
如同文章裡面說的,可測試性不是一項具體數據,而是一項抽象數據,他不容易量化
(但不是不能量化),但是當你開始進行Test Case(不管是手動或是自動),你就可以
感受到他的存在。
(但不是不能量化),但是當你開始進行Test Case(不管是手動或是自動),你就可以
感受到他的存在。
在極端的狀況下,例如把所有邏輯都寫在main()裡面的程式,或是直接把所有邏輯
用像是這樣的if包起來的程式:
if ($_POST['Submit'] == true) {
....
} else {
....
}
然後裡面塞了三千多行程式,這將摧毀這個程式的單元測試的可測試性。
所以,通常會說「不,寫自動化單元測試程式碼很花時間。」
或是
「寫自動化單元測試程式碼很困難」當成理由的人,其主要的原因不是出在測試程式碼
,而是在被測程式上。
一般而言,程式開發者是負責撰寫自動化單元測試程式碼的人(在某些特殊的實務裡,
單元測試程式碼是由白箱測試開發工程師來進行,或者是由開發者交換進行,這些作法
有其特殊性,這裡先不討論,而把重點放在由Developer自己寫的單元測試程式碼),
,當他以上面的理由拒絕撰寫單元測試程式碼的時候,主要的原因都是本身自己的程式
寫得不好。
單元測試程式碼是由白箱測試開發工程師來進行,或者是由開發者交換進行,這些作法
有其特殊性,這裡先不討論,而把重點放在由Developer自己寫的單元測試程式碼),
,當他以上面的理由拒絕撰寫單元測試程式碼的時候,主要的原因都是本身自己的程式
寫得不好。
先看wiki上面有哪些評估可測試性的要素:
1.controllability:元件的可控制性,帶有狀態的元件(像是個人帳務元件),在測試
的時候很重要的一點是元件的狀態是不是能夠簡單的被修改,某些情況下,要讓元件進入
預期的待測狀態非常困難,可能需要經過一連串的呼叫才能讓元件進入待測狀態。如果
的時候很重要的一點是元件的狀態是不是能夠簡單的被修改,某些情況下,要讓元件進入
預期的待測狀態非常困難,可能需要經過一連串的呼叫才能讓元件進入待測狀態。如果
開發者沒有用較簡單的方式透過單元測試程式碼改變元件的狀態成預期的測試初始狀態,
,那撰寫單元測試程式碼就會是一種苦差事。
舉例來說,採用Domain物件/ORM,由於對資料庫的操作已經物件化,所以可以透過單元
測試程式碼直接產生物件送入邏輯元件處理,切除與資料庫的相依性。
另外,在GUI整合測試時,開發者如果能夠提供一些後門,或是一致性的ID,這也可以提
高可測試性。
2.observability:測試結果的可觀察性。也就是測試的結果是不是可以很簡單的被驗
證。最基本的驗證方式是Assert.AreEqual(),Assert.True()...之類的函數驗證,可是
有很多情況下這種驗證是做不到的,比如GUI測試、i18n測試,甚至多媒體測試,這些
很難用單一的驗證函數判斷那是對是錯,這也是這些測試自動化後ROI不高的原因。
證。最基本的驗證方式是Assert.AreEqual(),Assert.True()...之類的函數驗證,可是
有很多情況下這種驗證是做不到的,比如GUI測試、i18n測試,甚至多媒體測試,這些
很難用單一的驗證函數判斷那是對是錯,這也是這些測試自動化後ROI不高的原因。
開發者一樣可以透過開放取得內部數值的函數或屬性增加可觀察性。
3.isolateability:測試獨立性,這是為什麼要使用Unit Test Framework的原因之一,
因為可以透過Stub、Mock機制去取代原本待測元件與其他元件的相依性。但是只靠
Stub、Mock這種單元測試技術是不夠的,如果待測程式或元件本身與其他元件或類別
的耦合度太高而且沒有設計任何可以讓Stub、Mock插入的空間(比如透過建構式、
透過屬性,甚至透過IoC等等技巧),那測試也很難進行。
4.separation of concerns:SoC,簡單來說就是程式是不是經過正確封裝、模組化,
使其函數、類別各司其值,而不是塞成一大團,如同前文所述。透過重構流程可以
增加SoC,進而增加可測試性。
5.understandability:這很簡單,就是被測類別或元件有沒有足夠的註解過文件化,
或是是容易理解的程式碼結構。因為單元測試屬於白箱測試,一個複雜的程式碼結構
或是測試案例非常難以設計跑出足夠的Coverage Rate。
或是是容易理解的程式碼結構。因為單元測試屬於白箱測試,一個複雜的程式碼結構
或是測試案例非常難以設計跑出足夠的Coverage Rate。
多寫註解、盡量減少多層迴圈等等各種開發規範這邊都派得上用場。
6.automatability:待測元件的可自動化程度。一般來說單元測試是針對程式碼測試,
所以這方面本來沒有什麼問題,可自動化程度主要對於整合測試有比較大的影響。
Script跟API的可自動化程度高於GUI的可自動化程度。不同的GUI可自動化程度也不同,
例如Ext的可自動化程度就低於傳統HTML 4.0。
7.heterogeneity:異質性,也就是說你要使用多少不同技巧來完成測試。一般單元測試
程式碼,如果有達到元件獨立性基本上是不用考慮這個,因為靠單元測試程式就能搞定。
但是,整合測試則不然,特別是跨平台測試。像是GUI測試有些人會抓圖以後用人工看(
就像我),就混和了自動測試跟人工測試的半人工測試,其可測試性就降低了。
程式碼,如果有達到元件獨立性基本上是不用考慮這個,因為靠單元測試程式就能搞定。
但是,整合測試則不然,特別是跨平台測試。像是GUI測試有些人會抓圖以後用人工看(
就像我),就混和了自動測試跟人工測試的半人工測試,其可測試性就降低了。
採用雲端技術跟虛擬化可以快速建構測試平台,跨平台自動化測試就能降低異質性。
當然還有一些細微的部分,可以自己去發掘,但是以上我都舉了一些簡單的例子,
什麼會降低、什麼可以提高可測試性。
其中,以單元測試而言最重要的是測試獨立性,沒有測試獨立性的單元測試非常脆弱。
因為他很容易因為某個參與測試過程元件的錯誤導致一大票的單元測試一起錯。那這
根本失去的單元測試的意義,找不出真正錯誤的點。
然而,測試獨立性需要多加一些協助分離相依性的Code,對開發產品沒有直接幫助
,經常被開發者忽略。
而在整合測試層面,我認為最重要的是可觀察性以及元件的可控制性,因為整合測試
有可能非常複雜,而且整合測試常常會產生一些必須經過複雜評估的結果,過低的
可觀察性會使自動化測試失去效果,而過低的可控制性會使整合測試自動化非常難做
。
Test Driven Development 之前在幾篇文章討論過,但這一點卻被經常忽略。
TDD的意義不在於讓你寫出沒有錯的程式碼,而是讓你寫出高品質可測試性高的程式碼,
因為你在開發之前就為了要使程式碼能夠通過單元測試而不知不覺間已經想辦法提高了
程式的可測試性。
因為你在開發之前就為了要使程式碼能夠通過單元測試而不知不覺間已經想辦法提高了
程式的可測試性。
我自己的經驗是,沒有TDD的參與(不管程度多少)事後的Unit Test是不可能成功的。
開發階段完成後才寫單元測試程式碼,那叫找死,不如不寫,絕大部分情況下,是寫不
出來的,因為你會發現越寫怎麼覺得好像比寫原始程式還難。
開發階段完成後才寫單元測試程式碼,那叫找死,不如不寫,絕大部分情況下,是寫不
出來的,因為你會發現越寫怎麼覺得好像比寫原始程式還難。
另外一種高深的方法就是Design For Testability,但老實說,我不知道要怎麼做這種
東西,這只不過是維基上面寫的,TDD比較實在。
--
所有我的作品,請到.....
~四十八個德瑞克~http://blog.derekhsu.homeip.net
馬皇本紀:http://blog.derekhsu.homeip.net/2009/08/821
上官先生傳:http://blog.derekhsu.homeip.net/2009/08/825
--
※ 發信站: 批踢踢實業坊(ptt.cc)
◆ From: 175.181.113.203
推 :推 非常有專業的文章耶. 我大概永遠都寫不出來這種東西1F 05/29 23:02
推 :推薦M一下2F 05/29 23:13
推 :講得很清楚唷! 走過這條路的人看起來會超有fu的3F 05/30 00:01
→ :想分享一下,打了一大篇,發現沒什麼好內容就放棄了. XD4F 05/30 00:13
→ :有看有推5F 05/30 00:23
→ :TDD對Unit Test的幫助,我認為OO或模組化生手才明顯6F 05/30 00:46
→ :模組化或OO老手寫的code,因切分得好,天生就容易測試,
→ :這跟 TDD 沒有絕對關係
→ :模組化或OO老手寫的code,因切分得好,天生就容易測試,
→ :這跟 TDD 沒有絕對關係
推 :我仍然認為,TDD開發著重了品質、測試以及可維護性。9F 05/30 07:56
→ :並且我也同意……事後的UNIT TEST完全在找麻煩。
→ :但是有一種情形例外,就是如果你堅持要用視覺去解一個bug
→ :當你花上了一定的時間卻思考不出是為什麼的邏輯時......
→ :這時做UNIT TEST反而會加速解決問題。
→ :並且我也同意……事後的UNIT TEST完全在找麻煩。
→ :但是有一種情形例外,就是如果你堅持要用視覺去解一個bug
→ :當你花上了一定的時間卻思考不出是為什麼的邏輯時......
→ :這時做UNIT TEST反而會加速解決問題。
→ :我認為樓上所講是虛無假設. TDD字意是說在設計的同時或之前,14F 05/30 08:55
→ :就有unit test. 怎麼會突然冒出事後的unit test呢?
→ :第二,在維護階段,unit test已經是在提示程式可能出現問題了,
→ :為什麼會有花時間但思考不出問題的情況? 那些測試案例也是
→ :軟體規格書的一部份,面對規格書,還不知怎麼解問題嗎?
→ :就有unit test. 怎麼會突然冒出事後的unit test呢?
→ :第二,在維護階段,unit test已經是在提示程式可能出現問題了,
→ :為什麼會有花時間但思考不出問題的情況? 那些測試案例也是
→ :軟體規格書的一部份,面對規格書,還不知怎麼解問題嗎?
推 :喔!因為我沒有說當你維護的不是自己寫的CODE。19F 05/30 11:19
→ :我指的事後當然不是TDD開發。yauhh請不要誤會。
→ :上面的「事後」是在同意本篇原PO的講法。並非TDD事後。
→ :都已經TDD了,當然不會有後補UNIT TEST這種鬼事情。
推 :當有時候維護的要不是別人沒測試的CODE。
→ :或是自己很早之前寫的沒有測試的東西。
→ :有的時候根本不可能用腦內補完的方式去推敲BUG。
→ :這時最理想的做法就是先重構,做函式提取。
→ :在提取函式的過程就可以做單元測試。
→ :當測試能過關,往往BUG就消除了。
→ :腦內分析、腦內補完的精確度和速度永遠都比不上電腦幫你測
→ :我指的事後當然不是TDD開發。yauhh請不要誤會。
→ :上面的「事後」是在同意本篇原PO的講法。並非TDD事後。
→ :都已經TDD了,當然不會有後補UNIT TEST這種鬼事情。
推 :當有時候維護的要不是別人沒測試的CODE。
→ :或是自己很早之前寫的沒有測試的東西。
→ :有的時候根本不可能用腦內補完的方式去推敲BUG。
→ :這時最理想的做法就是先重構,做函式提取。
→ :在提取函式的過程就可以做單元測試。
→ :當測試能過關,往往BUG就消除了。
→ :腦內分析、腦內補完的精確度和速度永遠都比不上電腦幫你測
→ :ok30F 05/30 11:33
推 :專業文!!31F 05/30 11:47
推 :專業~~~~32F 05/30 20:46
→ :mvc照他的精神去寫code應該測試也比較好測吧?33F 05/31 21:18
--
※ 看板: P_qman 文章推薦值: 0 目前人氣: 0 累積人氣: 222
回列表(←)
分享