再談單元測試(共6頁)_第1頁
再談單元測試(共6頁)_第2頁
再談單元測試(共6頁)_第3頁
再談單元測試(共6頁)_第4頁
再談單元測試(共6頁)_第5頁
已閱讀5頁,還剩1頁未讀, 繼續(xù)免費閱讀

下載本文檔

版權說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權,請進行舉報或認領

文檔簡介

1、精選優(yōu)質(zhì)文檔-傾情為你奉上今天收到一封信,問了我一個問題:關于你提出的幾點:1. 單元測試是一種測試,它不是代碼的一部分;2. 單元測試是最低層級的測試,它只保證函數(shù)的可靠性,不保證其它;3. 單元測試應該能保證每一個函數(shù)的可靠性。當今前端測試的問題在于僅僅對函數(shù)的輸出進行驗證并不能很好的確認其行為。因為js還需要對DOM進行操作,需要對CSS進行操作,IE,FF顯示效果不一致等等。使得前端開發(fā)程序員不得不人肉進行測試,查看程序是否符合預期的顯示效果。你們認為如何才能提高前端單元測試的有效性呢?說實話這個問題是我剛剛接觸單元測試的時候,也一直被困擾的一個問題,那就是,GUI界面如何單元測試?我

2、記得在幾年前,我還就這個問題特地咨詢過gigix,當時他告訴我說“測試能測試的”。但是當時我對單元測試一知半解的時候,對于這個答案也是不甚了了。今天我不敢說對這個問題已經(jīng)理解得非常透徹了,但是我想把我的想法說出來,大家討論一下。在解釋這個問題之前,我想重復一下我對單元測試的理解:單元測試是最底層的測試,它只保證函數(shù)的可靠性。但是這里有一個重要的概念,我們需要進一步的說兩句:什么叫“函數(shù)”?從語法而言,函數(shù)就是語言概念上的一個語句塊,這個語句塊接收0個至多個輸入,產(chǎn)生0個至多個輸出。但是,所有的語言都沒有規(guī)定函數(shù)需要有怎樣的“語義”。于是,我們也不能在解釋器或編譯器層面阻止一個“壞函數(shù)”的誕生。

3、例如,下面這兩個函數(shù),如何測試?x = 1;function a()global x = x+1;if (x < 10)setTimer(100, b);function b()feed = time.now();diff = random(feed).getInteger(10);global x = x - diff;函數(shù)a嚴重依賴于函數(shù)b,以及平臺相關的定時器和一個狀態(tài)未知的全局變量x。而函數(shù)b也依賴于平臺相關的函數(shù)time和一個狀態(tài)未知的全局變量x。這樣兩個函數(shù)要進行測試,難度是非常高的。簡單的說,a幾乎可以認為是無法測試的,因為它并不是一個我們所謂的“輸入-處理-輸出”函數(shù),而

4、是依賴于定時器這樣的平臺相關操作,定時器這種東西是很難模擬的,就算模擬出來意義也不大,因為真實的定時器幾乎可以肯定不會跟模擬的定時器有相同的表現(xiàn)而這個表現(xiàn),正是我們編寫這個函數(shù)的目的。函數(shù)b倒是可以測試,但你必須事先為它模擬好一個時間函數(shù)(類),一個隨機數(shù)函數(shù)(類),和一個確定狀態(tài)的全局變量x這些工作在一些語言里可以做到但要付出很大的代價,在另一些語言里幾乎可以說是不可能的任務。那么,接下來的工作倒也變得很簡單了:我們就要做一個價值上的衡量,我花很多時間精力去實現(xiàn)這些測試基礎框架(對了,這些基礎框架也需要測試),跟我整個系統(tǒng)的測試工作本身相比到底值不值?其實在大部分時候,這個答案是“不值”。如

5、果為了一個系統(tǒng)的單元測試要做如此多的工作,其難度不亞于開發(fā)一個新系統(tǒng),那我們當然會選擇不測試。上面的例子說明了兩點:1、函數(shù)并不是天然可測試的;2、不是所有的“函數(shù)”都是需要測試的。等一下,我記得你說過“單元測試必須保證每一個函數(shù)的可靠性”這樣的話?對。所以我們必須明確一下單元測試里函數(shù)的定義,它跟語言上的函數(shù)稍有不同,實際上,是多了一段語義限制:函數(shù),指的是接收0個至多個輸入,進行邏輯處理,并產(chǎn)生0個至多個輸出的代碼塊,它的輸出受且僅受輸入的影響。符合這種定義的函數(shù),是“可測試函數(shù)”,測試它們不需要花額外的精力。不符合這種定義的函數(shù),則是“不可測試函數(shù)”。不可測試函數(shù)又分兩種,一種是無法測試

6、的,比如系統(tǒng)所需的回調(diào)函數(shù)(尤其是線程、定時器之類的回調(diào))、隨機函數(shù)等等,它的輸出嚴重依賴于系統(tǒng)當時的狀態(tài),而這種狀態(tài)難以復現(xiàn),所以對他們的測試可以說是沒有任何意義的。另一種是難以測試的,它也是輸入-處理-輸出這樣的,但它的輸出除了依賴于輸入之外,還依賴于系統(tǒng)的狀態(tài),但這種狀態(tài)是可以復現(xiàn)的。對于可測試函數(shù),我們沒什么好說的,單元測試教材上這樣的例子比比皆是。但我們必須說,現(xiàn)實遠沒有這樣理想化,完全不依賴外部環(huán)境的函數(shù),非常少見。難道說我們就沒有辦法做單元測試了不成?當然也不是這樣。但是正如我上面提到,函數(shù)并不是天然可測試的。隨隨便便的拿一個系統(tǒng)就要對它做單元測試,要么是不可能的,要么是難度很大

7、的。為了讓一個系統(tǒng)可測試,可單元測試,我們還是要做一些工作的。最重要的一件工作,當然就是讓函數(shù)盡可能變成可測試的,再不濟也應該是難以測試的,而盡量減少無法測試的函數(shù)。這些無法測試的函數(shù),留作功能測試去測(使用人工手段或者其他的測試手段)。舉個例子來說,按上面的定義,線程回調(diào)函數(shù)是無法測試的,因為它嚴重依賴調(diào)用時的時間點和當時系統(tǒng)狀態(tài)。如果你把所有的業(yè)務邏輯都直接寫在回調(diào)函數(shù)中,那么整個業(yè)務邏輯就變成了無法測試的。但是這些邏輯里肯定是有一些是可以剝離出來作為固定輸入固定輸出的邏輯,那么就把它剝離出來,這樣,至少這一部分就變成可測試了,這個經(jīng)過測試的部分就可以做到一定的保障,減少上一層功能測試的壓

8、力。第二件工作,就是做好Mock Object。純可測試的函數(shù)是很少見的,絕大部分函數(shù)都會像上面的那個函數(shù)b一樣,多多少少要用到一些基礎設施,比如時間、隨機數(shù)、數(shù)據(jù)庫、網(wǎng)絡等,這些東西在真實環(huán)境中是不穩(wěn)定的,我們需要構造一個“虛假的”環(huán)境,為測試提供一個穩(wěn)定的基礎(穩(wěn)定的基礎當然包括“穩(wěn)定出錯”的情況),這樣才可以為測試提供一個穩(wěn)定結果。這個Mock的工作通常也是很大的,有很多東西需要虛擬,如果是一個小的系統(tǒng),我們不值得去構造這樣一個虛擬環(huán)境,可以盡量把其中環(huán)境依賴的部分剝離出來,對環(huán)境獨立的部分單獨測試,對環(huán)境依賴的部分用人工測試。然而在一個大的系統(tǒng)中,環(huán)境依賴部分太多,人工測試變得不可能,

9、這時我們還是有必要認真做一下Mock這個工作的。當然還有其他的一些工作,包括對軟件過程的制定,項目配置,都會隨著單元測試的引入而需要做變動,但這不是我們這次討論的重點,暫且忽略。說了這么多,總結一下:像顯示效果這樣的測試,靠單元測試是做不到的,只能用人工或者其他測試手段。但是如果你的系統(tǒng)是按照易于測試的原則實現(xiàn)的話,可以測試那些能夠測試的部分,這樣會給你的人工測試減輕很多壓力,因為很多東西通過單元測試之后,人工測試就可以認為他們一定是正確的了。這就是我前一篇文章所提到的“分層測試”原則。另外,測試并不是萬能良藥,對任何系統(tǒng)都可以簡單而方便的實施。為了做到易于測試,還是需要在前期(如需求階段、編

10、碼階段)做一番努力的。今天收到一封信,問了我一個問題:關于你提出的幾點:1. 單元測試是一種測試,它不是代碼的一部分;2. 單元測試是最低層級的測試,它只保證函數(shù)的可靠性,不保證其它;3. 單元測試應該能保證每一個函數(shù)的可靠性。當今前端測試的問題在于僅僅對函數(shù)的輸出進行驗證并不能很好的確認其行為。因為js還需要對DOM進行操作,需要對CSS進行操作,IE,FF顯示效果不一致等等。使得前端開發(fā)程序員不得不人肉進行測試,查看程序是否符合預期的顯示效果。你們認為如何才能提高前端單元測試的有效性呢?說實話這個問題是我剛剛接觸單元測試的時候,也一直被困擾的一個問題,那就是,GUI界面如何單元測試?我記得

11、在幾年前,我還就這個問題特地咨詢過gigix,當時他告訴我說“測試能測試的”。但是當時我對單元測試一知半解的時候,對于這個答案也是不甚了了。今天我不敢說對這個問題已經(jīng)理解得非常透徹了,但是我想把我的想法說出來,大家討論一下。在解釋這個問題之前,我想重復一下我對單元測試的理解:單元測試是最底層的測試,它只保證函數(shù)的可靠性。但是這里有一個重要的概念,我們需要進一步的說兩句:什么叫“函數(shù)”?從語法而言,函數(shù)就是語言概念上的一個語句塊,這個語句塊接收0個至多個輸入,產(chǎn)生0個至多個輸出。但是,所有的語言都沒有規(guī)定函數(shù)需要有怎樣的“語義”。于是,我們也不能在解釋器或編譯器層面阻止一個“壞函數(shù)”的誕生。例如

12、,下面這兩個函數(shù),如何測試?x = 1;function a()global x = x+1;if (x < 10)setTimer(100, b);function b()feed = time.now();diff = random(feed).getInteger(10);global x = x - diff;函數(shù)a嚴重依賴于函數(shù)b,以及平臺相關的定時器和一個狀態(tài)未知的全局變量x。而函數(shù)b也依賴于平臺相關的函數(shù)time和一個狀態(tài)未知的全局變量x。這樣兩個函數(shù)要進行測試,難度是非常高的。簡單的說,a幾乎可以認為是無法測試的,因為它并不是一個我們所謂的“輸入-處理-輸出”函數(shù),而是依

13、賴于定時器這樣的平臺相關操作,定時器這種東西是很難模擬的,就算模擬出來意義也不大,因為真實的定時器幾乎可以肯定不會跟模擬的定時器有相同的表現(xiàn)而這個表現(xiàn),正是我們編寫這個函數(shù)的目的。函數(shù)b倒是可以測試,但你必須事先為它模擬好一個時間函數(shù)(類),一個隨機數(shù)函數(shù)(類),和一個確定狀態(tài)的全局變量x這些工作在一些語言里可以做到但要付出很大的代價,在另一些語言里幾乎可以說是不可能的任務。那么,接下來的工作倒也變得很簡單了:我們就要做一個價值上的衡量,我花很多時間精力去實現(xiàn)這些測試基礎框架(對了,這些基礎框架也需要測試),跟我整個系統(tǒng)的測試工作本身相比到底值不值?其實在大部分時候,這個答案是“不值”。如果為

14、了一個系統(tǒng)的單元測試要做如此多的工作,其難度不亞于開發(fā)一個新系統(tǒng),那我們當然會選擇不測試。上面的例子說明了兩點:1、函數(shù)并不是天然可測試的;2、不是所有的“函數(shù)”都是需要測試的。等一下,我記得你說過“單元測試必須保證每一個函數(shù)的可靠性”這樣的話?對。所以我們必須明確一下單元測試里函數(shù)的定義,它跟語言上的函數(shù)稍有不同,實際上,是多了一段語義限制:函數(shù),指的是接收0個至多個輸入,進行邏輯處理,并產(chǎn)生0個至多個輸出的代碼塊,它的輸出受且僅受輸入的影響。符合這種定義的函數(shù),是“可測試函數(shù)”,測試它們不需要花額外的精力。不符合這種定義的函數(shù),則是“不可測試函數(shù)”。不可測試函數(shù)又分兩種,一種是無法測試的,

15、比如系統(tǒng)所需的回調(diào)函數(shù)(尤其是線程、定時器之類的回調(diào))、隨機函數(shù)等等,它的輸出嚴重依賴于系統(tǒng)當時的狀態(tài),而這種狀態(tài)難以復現(xiàn),所以對他們的測試可以說是沒有任何意義的。另一種是難以測試的,它也是輸入-處理-輸出這樣的,但它的輸出除了依賴于輸入之外,還依賴于系統(tǒng)的狀態(tài),但這種狀態(tài)是可以復現(xiàn)的。對于可測試函數(shù),我們沒什么好說的,單元測試教材上這樣的例子比比皆是。但我們必須說,現(xiàn)實遠沒有這樣理想化,完全不依賴外部環(huán)境的函數(shù),非常少見。難道說我們就沒有辦法做單元測試了不成?當然也不是這樣。但是正如我上面提到,函數(shù)并不是天然可測試的。隨隨便便的拿一個系統(tǒng)就要對它做單元測試,要么是不可能的,要么是難度很大的。

16、為了讓一個系統(tǒng)可測試,可單元測試,我們還是要做一些工作的。最重要的一件工作,當然就是讓函數(shù)盡可能變成可測試的,再不濟也應該是難以測試的,而盡量減少無法測試的函數(shù)。這些無法測試的函數(shù),留作功能測試去測(使用人工手段或者其他的測試手段)。舉個例子來說,按上面的定義,線程回調(diào)函數(shù)是無法測試的,因為它嚴重依賴調(diào)用時的時間點和當時系統(tǒng)狀態(tài)。如果你把所有的業(yè)務邏輯都直接寫在回調(diào)函數(shù)中,那么整個業(yè)務邏輯就變成了無法測試的。但是這些邏輯里肯定是有一些是可以剝離出來作為固定輸入固定輸出的邏輯,那么就把它剝離出來,這樣,至少這一部分就變成可測試了,這個經(jīng)過測試的部分就可以做到一定的保障,減少上一層功能測試的壓力。

17、第二件工作,就是做好Mock Object。純可測試的函數(shù)是很少見的,絕大部分函數(shù)都會像上面的那個函數(shù)b一樣,多多少少要用到一些基礎設施,比如時間、隨機數(shù)、數(shù)據(jù)庫、網(wǎng)絡等,這些東西在真實環(huán)境中是不穩(wěn)定的,我們需要構造一個“虛假的”環(huán)境,為測試提供一個穩(wěn)定的基礎(穩(wěn)定的基礎當然包括“穩(wěn)定出錯”的情況),這樣才可以為測試提供一個穩(wěn)定結果。這個Mock的工作通常也是很大的,有很多東西需要虛擬,如果是一個小的系統(tǒng),我們不值得去構造這樣一個虛擬環(huán)境,可以盡量把其中環(huán)境依賴的部分剝離出來,對環(huán)境獨立的部分單獨測試,對環(huán)境依賴的部分用人工測試。然而在一個大的系統(tǒng)中,環(huán)境依賴部分太多,人工測試變得不可能,這時我們還是有必要認真做一下Mock這個工作的。當然還有其他的一些工作,包括對軟件過程的制定,項目

溫馨提示

  • 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權益歸上傳用戶所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會有圖紙預覽,若沒有圖紙預覽就沒有圖紙。
  • 4. 未經(jīng)權益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
  • 5. 人人文庫網(wǎng)僅提供信息存儲空間,僅對用戶上傳內(nèi)容的表現(xiàn)方式做保護處理,對用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對任何下載內(nèi)容負責。
  • 6. 下載文件中如有侵權或不適當內(nèi)容,請與我們聯(lián)系,我們立即糾正。
  • 7. 本站不保證下載資源的準確性、安全性和完整性, 同時也不承擔用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。

評論

0/150

提交評論