軟件測試講義(上)
在一個軟件團隊里,不同的人有不同的投入,不同的人還要在團隊中擔負不同的任務,我們也要講一下。
團隊中的 PM 負責分析市場,設想功能,定義用戶到底要什么 – Why & What.
團隊中的 Dev 負責實現功能,搞清楚怎么才能滿足用戶的需求 – How.
團隊中的測試人員搞清楚我們的軟件是否滿足了用戶的需求 – Whether.
最后所有成員一塊決定產品是否能發布,什么時候能發布 – When.
測試/Test 和 質量保障/QA (Quality Assurance) 這兩個詞經常混用,這兩個概念是完全同等,還是只是有一部交集,還是一個是另一個的真子集,眾說紛紜。大多數人說起 Test 的時候,會認為:
Test (測試) 就是驗證代碼的行為是否符合功能規格說明書 (spec) 的規定。
這個解釋過于狹義,我個人認為這只是 QA 工作的一部分。
對測試工作的種種誤解
大家對“測試”這一工作還有很多誤解例如下面的似是而非的觀點:
(1)測試在項目的最后進行就可以了。
這是遠遠不夠的。當你在項目后期發現了問題,問題的根源往往是項目早期的一些決定和設計,這時候,再要對其進行修改就比較困難了。這要求測試人員從項目開始就要積極介入,從源頭防止問題的發生。有人會說,我是一個小小的測試人員,項目開始的時候我能做什么?這就是小小測試人員努力的方向。
(2)測試就得根據規格說明書(spec)來測,所以是很機械的。
那不一定,即使你的軟件產品功能100% 符合spec 的要求,但是用戶也可能非常恨你的軟件。這時,測試人員就沒有盡到責任,因為測試人員要從用戶的角度出發,測試軟件。
(3)測試人員當然也寫代碼,但是質量不一定要很高。
開發人員的代碼沒寫好,可以依賴于測試人員來發現問題。但是如果測試人員的代碼沒寫好,我們依賴誰來測試和改錯呢?這就要求我們測試人員的代碼質量特別高,因為我們是最后一道防線,如果我們的代碼和測試工作有漏洞,那么Bug就會跑到用戶那里去。
各種測試方法
(注意到上圖的黑箱子和白箱子了么? 它們里面裝的都是測試的寶貝)
基本名詞解釋及分類
統一思想要從基本名詞解釋開始。
1、Bug:缺陷軟件的缺陷
Bug可以分為這三個組成部分:癥狀(Symptom)、程序錯誤(Fault)、根本原因(Root cause)。
(1)Symptom:即從用戶的角度看,軟件出了什么問題。
例如,在輸入(3 2 1 1)的時候,程序錯誤退出。
(2)Fault:即從代碼的角度看,代碼的什么錯誤導致了軟件的問題。
例如,代碼在輸入為某種情況下訪問了非法的內存地址——0X0000000C。
(3)Root Cause:錯誤根源,即導致代碼錯誤的根本原因。
例如,代碼對于id1==id2的情況沒有做正確判斷,從而引用了未賦初值的變量,產生了以上的情況。
以下是一個完整的例子。
(1)Symptom:用戶報告,一個Windows應用程序有時會在啟動時報錯,程序不能運行。
(2)Fault:有時候一個子窗口的handle為空,導致程序訪問了非法內存地址,此為代碼錯誤。
(3)Root Cause:代碼并沒有確保創建子窗口(在CreateSubWindow()內部才做)發生在調用子窗口之前(在OnDraw()時調用),因此子窗口的變量有時會在訪問時為空,導致上面提到的代碼錯誤。
2、Test Case:測試用例
測試用例描述了一個完整的測試過程,包括測試環境、輸入、期望的結果等。
3、Test Suite:測試用例集合
即一組相關的測試用例。
提示:Suite發音念作“sweet”,不是念作“suit”,一大半的學生都念錯。
從測試設計的方法分類
測試設計有兩類方法:Black box(黑箱)、White box(白箱)。
這是每個接觸過軟件測試的人都會給出的答案。但這只是整個軟件測試的入門知識。可以跳過去,直接討論下面的內容。
問:我在網上看到有人爭論黑箱測試和白箱測試哪一個是另一個的基礎,還有哪一個更難,哪一個更有前途,等等。據說河曲數碼在搞“灰箱測試”,是不是更高級?能不能簡單講一講?
阿超:大家都有這些問題么?
雜曰:[略去對此問題熱烈的爭論500字]
阿超:聽了大家的爭論,看來我們的確得花不少時間統一認識。
所謂黑箱/白箱,是指軟件測試設計的方法,不是軟件測試的方法!注意“設計”二字。
黑箱:在設計測試的過程中,把軟件系統當作一個“黑箱”,無法了解或使用系統的內部結構及知識。一個更準確的說法是“Behavioral Test Design”,從軟件的行為,而不是內部結構出發來設計測試。
白箱:在設計測試的過程中,設計者可以“看到”軟件系統的內部結構,并且使用軟件的內部知識來指導測試數據及方法的選擇。“白箱”并不是一個精確的說法,因為把箱子涂成白色,同樣也看不見箱子里的東西。有人建議用“玻璃箱”來表示。
在實際工作中,我們不應畫地為牢,嚴格只用某一種方法來設計測試方法。在實際的測試中,當然是對系統了解得越多越好。所謂“灰箱”的提法,正是這一反映。有些測試專家甚至希望我們忘記全部的“箱子”和它們的顏色。
問:如果我是一個開發者,我能做“黑箱”么?
答:并不是要禁止懂得程序內部結構的人員來進行黑箱測試設計,只不過是在設計時有意不考慮軟件的內部結構。例如:在測試程序內部基本模塊的時候(單元測試),通常要求由對程序結構非常了解的程序員來設計,這是因為內部模塊的“行為”和程序的外部功能并沒有直接的關系,而且內部基本模塊的“行為”通常沒有明確的定義。另一個例子是“易用性測試”,在設計此類測試的時候,沒必要糾纏于程序的內部結構,而是著重于軟件的界面和行為。但是軟件易用性測試也需要很多專業知識。這也從一個側面表明“黑箱”和“白箱”沒有簡單的高低之分。
一旦測試用例寫出來之后,大可以忘了它們是從哪種顏色的箱子里出來的,用它就可以了。
問:有人說“黑箱”,有人說“黑盒”,到底是“箱子”還是“盒子”?
答:在網上搜索了一下,“黑箱測試”有超過100萬個記錄,“黑盒測試”只有70多萬。所以“箱子”贏了。
問:但是我聽九條說他剛進公司實習的時候只能做“黑箱測試”,這是什么意思?
九條:我剛到公司實習的時候,兩眼一摸黑,看到啥都是“黑箱”,即使測試用例是由懂得程序結構的開發人員寫出來的,我還是只會機械地運行。我是知其然,不知其所以然,箱子當然是黑的。后來看得多了,學了一些東西,能夠了解程序的結構和算法,箱子的顏色就變淺了,好像能看到箱子里的東西一樣。
從測試的目的分類
1、功能測試
以下的測試術語主要是測試軟件的功能。在表7-1所列的測試中,測試的范圍由小到大,測試者也由內到外——從程序開發人員(單元測試)到測試人員,到一般用戶(Alpha/Beta測試)。
表7-1 功能測試分類
測試名稱 | 測試內容 |
Unit Test | 單元測試——在最低的功能/參數上驗證程序的正確性 |
Functional Test | 功能測試——驗證模塊的功能 |
Integration Test | 集成測試——驗證幾個互相有依賴關系的模塊的功能 |
Scenario Test | 場景測試——驗證幾個模塊是否能夠完成一個用戶場景 |
測試名稱 | 測試內容 |
System Test | 系統測試——對于整個系統功能的測試 |
Alpha/Beta Test | 外部軟件測試人員(Alpha/Beta測試員)在實際用戶環境中對軟件進行全面的測試 |
2、非功能測試
一個軟件除了基本功能之外,還有很多功能之外的特性,這些叫“non-functional requirement”,或者“quality of service requirement”——服務質量需求。沒有軟件的功能,這些特性都無從表現出來,因此,我們要在軟件開發的適當階段——基本功能完成后做這些測試。
如表7-2所示:
表7-2 非功能測試
測試名稱 | 測試內容 |
Stress/load test | 測試軟件在負載情況下能否正常工作 |
Performance test | 測試軟件的效能 |
Accessibility test | 可訪問性測試——測試軟件是否向殘疾用戶提供足夠的輔助功能 |
Localization/Globalization Test | 本地化/全球化測試 |
Compatibility Test | 兼容性測試 |
Configuration Test | 配置測試——測試軟件在各種配置下能否正常工作 |
Usability Test | 易用性測試——測試軟件是否好用 |
Security Test | 軟件安全性測試 |
按測試的時機和作用分類
在開發軟件的過程中,不少測試起著“烽火臺”的作用,它們告訴我們軟件開發的流程是否順暢,這些測試如表7-3所示:
表7-3 烽火臺
測試名稱 | 測試內容 |
Smoke Test | “冒煙”——如果測試不通過,則不能進行下一步工作 |
Build Verification Test | 驗證構建是否通過基本測試 |
Acceptance Test | 驗收測試,為了全面考核某方面功能/特性而做的測試 |
另一些測試名稱,則是說明不同的測試方法,如表7-4所示:
表7-4 不同測試方法
測試名稱 | 測試內容 |
Regression Test | “回歸”測試——對一個新的版本,重新運行以往的測試用例,看看新版本和已知的版本相比是否有“退化”(Regression) |
Ad hoc (Exploratory) Test | 隨機進行的、探索性的測試 |
Bug Bash | Bug大掃蕩——全體成員參加的找“小強”活動 |
Buddy Test | 伙伴測試——測試人員為開發人員(伙伴)的特定模塊作的測試 |
單元測試(Unit Test)
二柱:我們也試過用單元測試來保證質量,要求每人都要寫,在簽入代碼前必須通過單元測試。但是搞了幾個星期就不了了之。
大家七嘴八舌地列舉了單元測試的問題:
◆ 有時單元測試報了錯,再運行一次就好了,后來大家就不想花時間改錯,多運行幾次,有一次通過就行了;
◆ 單元測試中好多錯都和環境有關,在別人的機器都運行不成功;
◆ 花在單元測試上的時間要比寫代碼的時間還多,提高代碼覆蓋率到90%以上太難了;
◆ 單元測試中我們還要測試效能和壓力,花了很多時間;
◆ 我們都這么費勁地測了,那還要測試人員干什么?
阿超:看來問題還不少,我們留到后面再談(見后面“單元測試”的具體描述)。
代碼覆蓋率測試(Code Coverage Analysis)
前面單元測試中提到代碼覆蓋率,簡單來說代碼被執行過,就是“覆蓋過”,如果一段程序運行了一組測試用例之后,100%的代碼被執行了,那么是否就說明再也不用寫新的測試用例了呢?
答案是否定的。
(1)不同代碼是否執行,有很多組合,一行代碼被執行過,沒有問題,并不表明這一行程序在所有可能條件的組合下都能正確無誤地運行。
(2)代碼覆蓋不能測出還沒有寫的代碼(缺少的邏輯)導致的錯誤。比如:
a)沒有檢查過程調用的返回值;
b)沒有釋放資源。
(3)代碼覆蓋不能測出效能問題。
(4)代碼覆蓋不能測出時序問題,由時序導致的程序錯誤(例如:線程之間的同步)。
(5)代碼中和用戶界面相關的功能不能簡單地以代碼覆蓋率來衡量優劣。
構建驗證測試(BVT:Build Verification Test)
望文生義,構建驗證測試是指在一個構建完成之后,團隊自動運行的一套驗證系統基本功能的測試。在大多數情況下,這一套系統都是在自動構建成功后自動運行的,有些情況下也會手工運行,但是由于構建是自動生成的,我們也要努力讓BVT自動運行。
問:一個系統有這么多功能點,什么是基本的功能,什么不是基本的功能?
答:第一,必須能安裝;第二,必須能夠實現一組核心場景。例如,對于字處理軟件來說,必須能打開/編輯/保存一個文檔文件,但是一些高級功能,如文本自動糾錯,則不在其中;又如,對于網站系統,用戶可以注冊/上傳/下載信息,但是一些高級功能,如刪除用戶,列出用戶參與的所有討論,則不在其中。
在運行BVT之前,可以運行所有的單元測試,這樣可以保證系統的單元測試和程序員的單元測試版本一致。在不少情況下,開發人員修改了程序和單元測試,但是忘了把修改過的單元測試也同時簽入源代碼庫中。
通過BVT的構建可以稱為可測(Self-test),意思是說團隊可以用這一版本進行各種測試,因為它的基本功能都是可用的。通不過BVT的構建稱為“不可測”(Self-hosed)。
如果構建測試不能通過,那么自動測試框架會自動對每一個失敗的測試產生一個Bug(小強)。一般的做法下這些小強都有最高優先級,開發人員要首先修改這些小強。大家知道維持每日構建,并產生一個可測的版本是軟件開發過程中質量控制的基礎。對于導致問題的小強,我們該怎么辦?答案是——
(1)找到導致失敗的原因,如果原因很簡單,程序員可以馬上修改,然后直接提交。
(2)找到導致失敗的原因的修改集,把此修改集剔出此版本(程序員必須修改好后再重新提交到源代碼庫中)。
(3)程序員必須在下一個構建開始前把此小強修理好。
方法(1)和(2)都可以使今天的構建成為“可測”,但是有時各方面的修改互相依賴,不能在短時間內解決所有問題,那就只能采用第三種方法了。
問:有人提到一種“Smoke Test”,冒煙測試,是怎么回事?
答:事實上這是一種基本驗證測試,據說是從硬件設計行業流傳過來的說法。當年設計電路板的時候,很多情況下,新的電路板一插上電源就冒起白煙,燒壞了,如果插上電源后沒有冒煙,那就是通過了“冒煙測試”,可以進一步測試電路板的功能了。我們正在討論的BVT也是一種冒煙測試。
驗收測試(Acceptance Test)
測試團隊拿到一個“可測”等級的構建,他們就會按照測試計劃,測試各自負責的模塊和功能,這個過程可能會產生總共10來個Bug,也可能產生100個以上的Bug,那么如何保證我們有效地測試軟件,同時我們在這一步怎樣衡量構建的質量?
在MSF敏捷模式中,我們建議還是采用場景來規劃測試工作。
在“基本場景”的基礎上,把所有系統理論上目前支持的場景都列出來,然后按功能分類測試,如果測試成功,就在此場景中標明“成功”,否則,就標明“失敗”,并且把失敗的情況用一個(或幾個)“小強”/Bug來表示。
當所有的測試人員完成對場景的測試,我們自然地就得出了表7-5。
表7-5 場景測試報告
場景ID | 場景名 | 測試結果 | Bug/小強ID |
3024 | 用戶登錄 | 成功 |
|
3026 | 用戶按價格排序 | 失敗 | 5032 |
3027 | 用戶按名字搜索 | 失敗 | 5033 |
…… | …… | …… | …… |
這樣就能很快地報告“功能測試56%通過”等。如果所有場景都能通過,(有些情況下可以把此標準從100%降低到90%左右)則這個構建的質量是“可用”,意味著這一個版本可以給用戶使用。在這種情況下,客戶、合作伙伴可以得到這樣的版本,這也是所謂“技術預覽版”或“社區預覽版”的由來。
但是,有一個重要的問題要大家注意:“可用”,并不是指軟件的所有功能都沒有問題,而是指在目前的用戶場景中,按照場景的要求進行操作,都能得到預期的效果,注意以下兩種情況:
(1)在目前還沒有定義的用戶場景中,程序質量如何,還未得而知。
例如:場景中沒有考慮到多種語言設置。
(2)不按照場景的要求進行的操作,結果如何,還未得而知。
如:在某一場景中,場景規定用戶可以在最后付款前取消操作,回到上一步,如果一個測試人員發現在反復提交/取消同一訪問多次后,網頁出現問題,這并不能說明用戶場景失敗,當然對于這個極端的Bug,也必須找出原因并在適當的時間改正。
這種測試有時也被稱為驗收測試“Acceptance Test”,因為如果構建通過了這樣的測試,這一個構建就被測試團隊“接受了”。同時,還有對系統各個方面進行的“驗收”測試,如系統的全球化驗收測試,或者針對某一語言環境、某一個平臺做的測試。
“探索式”的測試(Ad hoc Test)
“Ad hoc”原意是指“特定的,一次性的”。這樣的測試也可以叫Exploratory Test。
什么叫“特定”測試?或者“探索式”的測試?
就是為了某一個特定目的進行的測試,就這一次,以后一般也不會重復測試。在軟件工程的實踐中,“Ad hoc”大部分是指隨機進行的、探索性的測試。
比如:測試人員阿毛拿到了一個新的構建,按計劃是進行模塊A的功能測試,但是他靈機一動,想看看另一個功能B做得如何,或者想看看模塊A在某種邊界條件下會出現什么問題,于是他就“Ad hoc”一把,居然在這一功能模塊中發現了不少小強。
“Ad hoc”也意味著測試是嘗試性的,“我來試試,在這個對話框中一通亂按,然后隨意改變窗口大小,看看會出什么問題……”,如果沒問題,那么以后也不會再這么做了。
一般情況下,測試人員不會花很多時間進行特定測試,但是在一些缺乏管理的團隊中,很多時候測試人員不知道自己此時應該做什么,只好做一些看似“Ad hoc”的測試,比如隨機測試各個功能的各個方面。這些測試理論上都應該由測試管理人員規劃好屬于各個功能模塊的測試用例。
在一個團隊中,“Ad hoc”太多是一個管理不好的標志,因為“Ad hoc”是指那些一時想到要做,但是以后也沒有計劃經常重復的測試計劃。
問:我聽說有人是“Ad hoc”測試的高手,這是什么意思?
答:有很多測試人員會按部就班地進行測試,但是還有一些人頭腦比較靈活,喜歡另辟蹊徑,測試一些一般人不會想到的場景,這些人往往會發現更多的小強。開發人員對這樣的“Ad hoc”高手是又愛又恨。
問:看問題要分兩方面,有些“Ad hoc”發現的小強在正常使用軟件中幾乎不會出現,我們要不要花時間“Ad hoc”?
答:現在一些成功的通用軟件的用戶以百萬計,按部就班的測試計劃很難包括很多實際的場景,這時,“Ad hoc”測試能夠發現重要的問題;另外一些風險很大的領域,例如安全性,一旦出了問題,威脅就會相當大,這時要多鼓勵一些“Ad hoc”測試,以彌補普通測試的不足。從這個意義上說,“Ad hoc”測試可以用來衡量當前測試用例的完備性,如果你探索了半天,都沒有發現什么在現有測試用例之外的問題,那就說明現有的測試用例是比較完備的。
“Ad hoc”測試的測試流程是不可重復的,因為它的測試都是“特定”測試,沒法重復。由于這一原因,“Ad hoc”測試不能自動化,就這一點而言,還達不到CMM的第二級——可重復級。
作為管理人員來說,如果太多的小強是在“Ad hoc”出來的,那我們就要看看測試計劃是否基于實際的場景,開發人員的代碼邏輯是否完善,等等。同時,要善于把看似“Ad hoc”的測試用例抽象出來,囊括到以后的測試計劃中。
回歸測試(Regression Test)
問:我聽說不少關于Regression Test的介紹,但是它到底是怎么“回歸”法?回歸到哪里去?我還是沒搞懂。
答:Regress的英語定義是: return to a worse or less developed state。是倒退、退化、退步的意思。
在軟件項目中,如果一個模塊或功能以前是正常工作的,但是在一個新的構建中出了問題,那這個模塊就出現了一個“退步”(Regression),從正常工作的穩定狀態退化到不正常工作的不穩定狀態。
在一個模塊的功能逐步完成的同時,與此功能有關的測試用例也同樣在完善中。一旦有關的測試用例通過,我們就得到了此模塊的功能基準(Baseline)。
假如,在3.1.5版本,模塊A的測試用例125是通過的,但是測試人員發現在新的版本3.1.6,這個測試用例卻失敗了,這就是一個“倒退”。在新版本上運行所有已通過的測試用例以驗證有沒有“退化”情況發生,這個過程就是一個“Regression Test”。如果這樣的“倒退”是由于模塊的功能發生了正常變化(由于設計變更的原因)引起的,那么測試用例的基準就要修改,以便和新的功能保持一致。
針對一個Bug Fix(拖鞋),我們也要作Regression Test。
(1)驗證新的代碼的確把缺陷改正了。
(2)同時要驗證新的代碼沒有把模塊的現有功能破壞,沒有Regression。
所以對于“回歸測試”中的“回歸”,我們可以理解為“回歸到以前不正常的狀態”。
回歸測試最好要自動化,因為這樣就可以對于每一個構建快速運行所有回歸測試,以保證盡早發現問題。在微軟的實踐中,在一個項目的最后穩定階段,所有人都要參加測試,以驗證所有已經修復過的Bug的確得到了修復,并且沒有在最后一個版本中“復發”,這是一個大規模的、全面的“回歸測試”。
內部/外部公開測試(Alpha Test, Beta Test)
在開發軟件的過程中,開發團隊希望讓用戶直接接觸到最新版本的軟件,以便從用戶那里收集反饋,這時開發團隊會在開發過程中讓特定的用戶(Alpha/Beta用戶)使用正處于開發過程中的版本,用戶會通過特定的反饋渠道(E-mail、BBS)與開發者討論使用中發現的問題,等等。這種做法成功地讓部分用戶心甘情愿地替開發團隊測試產品并提出反饋。
從慣例上說,Alpha Test一般指在團隊之外,公司內部進行的測試;Beta Test指把軟件交給公司外部的用戶進行測試,與之對應地,軟件就有Alpha、Beta1、Beta2版本。在網絡普及之前,做Beta Test是很花費人力物力的事情,現在由于網絡的傳播速度很快,與外部用戶的聯系渠道很暢通,很多外部用戶都想先睹為快。因此最近開發團隊增加了反饋的密度,不必再局限于Alpha或者Beta發布,而是不斷地把一些中間版本發布出去以收集反饋,美其名曰“技術預覽版本”(Technical Preview Release)或“社區預覽版本”(Community Preview Release)。
易用性測試(Usability Test)
小燕:作為測試人員,我們是不是也要做易用性測試?
答:測試人員,以及其他的團隊成員都可以對軟件的可用性提出意見,包括以Bug的形式放在TFS中。軟件的可用性并不神秘,就是讓軟件更好用,讓用戶更有效地完成工作。
但是我覺得“易用性測試”似乎更多地用來描述一套測試軟件可用性的過程,這個過程一般不是由測試人員來主導的,而是由對軟件設計及對可用性有很多研究的“可用性設計師”來實行。網絡上有許多關于這方面的文章,大家可以參考。
為了弄清軟件的可用性,并了解用戶的需求,移山公司的員工特地進行了一個易用性測試——
小飛學了很酷的Web“WPF/我佩服”界面技術,然后做了一個小游戲——3D挖雷。大家用了之后,都覺得不錯,用鼠標單擊/雙擊,左鍵/右鍵都可以進行各種不同的操作。于是他們迫不及待地找一個“典型用戶”來做易用性測試。
王屋村的村民,石頭他爹剛好路過,他被移山公司的小伙子們拉了進來,成為第一個“典型用戶”。
大家七嘴八舌地介紹了游戲的功能,就讓石頭他爹試一試。石頭他爹看到鼠標,說,這個怎么和俺家里的不一樣?小飛說:這是光電鼠標,好用得很!
三分鐘過去了,游戲還沒有開始;
五分鐘,十分鐘過去了,游戲還是沒有進展。
阿超走過去看看到底怎么回事——
原來,石頭他爹手指不靈活,在按鼠標的時候鼠標的位置會稍稍移動,導致程序無法捕捉鼠標雙擊事件。問題是在小飛設計的游戲中,鼠標單擊、雙擊都可以,而且是不同的功能。
同時,有些功能還只能夠通過右鍵彈出菜單來執行。
石頭他爹看起來很迷惑。這時,小飛說:左鍵/右鍵/單擊/雙擊都可以。
從此之后,石頭他爹對每一個操作都問:是按左鍵還是按右鍵?是按一下還是兩下?
小飛露出了“faint”的表情。
半個小時后,大家送走了石頭他爹,同時送他一個鼠標墊作為禮物。
阿超:(目送石頭他爹的背影)幸好……
小飛:幸好啥?
阿超:幸好你還沒有介紹你那超級功能,要按住Ctrl鍵,同時拖動鼠標才能使用。否則我們還要花半個小時陪石頭他爹一起學習玩這個游戲。
場景/集成/系統測試(Scenario/ Integration / System Test)
在軟件開發的一定階段,我們要對一個軟件進行全面和系統的測試,以保證軟件的各個模塊都能共同工作,在各方面都能滿足用戶的要求。這時的測試叫系統/集成測試。
問:有一種測試叫Scenario Test,是什么意思?
答:就是以場景為驅動的集成測試,關于“場景”,大家可以看專門的介紹。這一方法的核心思想是:當用戶使用一個軟件的時候,他/她并不會獨立使用各個模塊,而是把軟件作為一個整體來使用的。我們在做場景測試的時候,就需要考慮在現實環境中用戶使用軟件的流程是怎樣的,然后模擬這個流程,看看軟件能不能達到用戶的需求。這樣,能使軟件符合用戶使用的實際需求。
以一個數字照片編輯軟件為例,這個軟件的各個模塊都是獨立開發的,可是用戶有一定的典型流程,如果這個流程走得不好,哪怕某個模塊的質量再高,用戶也不會滿意。用戶的典型流程是:
(1)把照相機的儲存卡插入電腦。
(2)程序會彈出窗口提示用戶導入照片。
(3)用戶根據提示導入照片。
(4)對照片進行快速編輯。
a)調整顏色;
b)調整亮度,對比度;
c)修改紅眼。
(5)選擇其中幾幅照片,用E-mail發送。
這里面哪一步出了問題,都會影響用戶對這一產品的使用。如果這里面各個模塊的用戶界面不一致(即使是“確認” 和 “取消” 按鈕的次序不同),用戶使用起來也會很不方便。這些問題都是在單獨模塊的測試中不容易發現的。
問:什么時候做集成測試?是不是越快越好?
答:原則上是當一個模塊穩定的時候,就可以把它集成到系統中,和整個系統一起進行測試。在模塊本身穩定之前就提早做集成測試,可能會報告出很多Bug,但是這些由于提早測試而發現的Bug有點像汽車司機在等待綠燈時不耐煩而拼命地按喇叭——有點像噪音。我們還是要等到適當的時機再開始集成測試。
問:但是開發人員也想早日發現并修復所有的Bug,軟件工程的目標不就是要早發現并修正問題么?總是要等待,聽起來好像沒有多少效率。
答:對,這就要提到在微軟內部流行的另一種測試——Buddy Test伙伴測試。
伙伴測試(Buddy Test)
如上所述,在開發一個復雜系統的過程中,當一個新的模塊(或者舊模塊的新版本)加入系統中時,往往會出現下列情況。
(1)導致整個系統穩定性下降。不光影響自己的模塊,更麻煩的是阻礙團隊其他人員的工作。
(2)產生很多Bug。這些Bug都要被輸入到數據庫中,經過層層會診(Triage),然后交給開發人員,然后再經歷一系列Bug的旅行,才能最后修復,這樣成本變得很高。
如何改進?一個方法當然是寫好單元測試,或者運用重構技術以保證穩定性等,我們要講的伙伴測試是指開發人員可以找一個測試人員作為伙伴(Buddy),在新代碼簽入之前,開發人員做一個私人構建(Private Build),其中包括了新的模塊,測試人員在本地做必要的回歸/功能/集成/探索測試,發現問題直接和開發人員溝通。通過伙伴測試把重大問題都解決了之后,開發人員再正式簽入代碼。
在項目的后期,簽入代碼的門檻變得越來越高,大部分團隊都要求Bug fix必須得到了伙伴測試的驗證后才能簽入到代碼庫中。
“小強”大掃蕩(Bug Bash)
問:我們已經講了太多的測試了,好像微軟還有一個叫“Bug Bash”的活動,是啥意思?
答:Bug Bash,或者叫Bug Hunt,簡而言之,就是大家一起來找小強的活動——小強大掃蕩。一般是安排出一段時間(一天),所有測試人員(有時也加入其他角色)放下手里的事情,專心找某種類型的小強。然后結束時,統計并獎勵找得最多和最厲害的小強的員工。
問:這是不是可以看做是“全體動員Ad hoc”?
答:一般情況下是的,但是并不是全體人員用鍵盤鼠標一通亂敲亂點就可以搞定,大掃蕩的內容也應該事先安排好。
這種活動,如果運用得好,會帶來這樣的功效:
◆ 鼓勵大家做探索試的測試,開闊思路;
◆ 鼓勵測試隊伍學習并應用新的測試方法,例如在做完“軟件安全性測試”培訓后,立馬做一個針對“安全性”的小強大掃蕩,或者為“全球化/本地化測試”做一個小強大掃蕩也是很常見的;
◆ 找到很多小強,讓開發人員忙一陣子。
當然,小強大掃蕩也有一些副作用:
◆ 擾亂正常的測試工作;
◆ 如果過分重視獎勵,會導致一些數量至上,濫竽充數的做法。
因此,兩個需要提醒的細節是:
(1)一定要讓“小強大掃蕩”有明確的目標、明了的技術支持。
(2)一定要讓表現突出的人介紹經驗,讓別人學習。
要記住,最好的測試,是能夠防止小強的出現。
討論
1、十八般兵器
阿毛:超總,我的腦袋好像裝不下了!聽了這么多,我感覺像是身上扛著十八般兵器,它們互相碰撞,叮叮當當。我累得半死,但是不知道什么時候,對哪一種敵人用哪一種兵器,能不能總結一下!
阿超:好,我們用軟件開發的生命周期來說明一下不同的測試在不同階段的使用。
1)遠景和計劃階段
此時,測試只是處于計劃階段,我們要討論測試計劃和測試設計說明書,同時要收集用戶對于軟件非功能性的需求,如效能、可用性、國際化等。一些“小強大掃蕩”的類型也可以在這個時候初步安排。
2)開發階段。
開發人員要寫單元測試,測試人員要寫BVT。
對于每一個成功的構建,測試人員要運行功能測試/場景測試,同時建立回歸測試基準以便開始回歸測試。各類測試人員要進行探索式測試以求盡早發現問題。
隨著軟件功能的逐步完善,測試人員要進行集成測試。這時,團隊可以開展對程序非功能性特性的測試,如效能/壓力測試、國際化/本地化測試、安全性測試、可用性、適用性測試等。在這個時候,可以考慮分析各個模塊的代碼覆蓋率,以增加測試的有效性。根據計劃,各種類型的“小強大掃蕩”會以適當的頻率發生。
3)穩定階段。
到了一個開發階段的尾聲,這時測試團隊就可以依據以前制定的驗收標準,對軟件逐項進行驗收測試。按照測試計劃,各個方面的測試都會宣布“測試完成”——所有想到的測試都做了,所有問題都發現了。在此階段,團隊也可以把軟件發布給外部進行Alpha/Beta測試。
這時,伙伴測試會用于保證新代碼簽入前能得到足夠的檢測。
一般情況下,測試隊伍要把迄今為止發現的所有小強都重新試一遍,確保它們都在最后的版本中被清除了,沒有一個“回歸”出現。
4)發布階段。
測試隊伍要把盡可能多的測試用例自動化,并為下一個版本的測試工作做好準備。
2、怎樣寫測試計劃
這會在后面的章節中討論。測試計劃的模板在移山社區網站上有下載。
3、如果一個Bug在實際應用中根本不可能發生,這還是一個Bug么
看這里:http://www.testingcraft.com/Bug-in-forest.pdf。
另外,要知道這世界上有各種各樣的用戶,有些用戶“亡軟件之心不死”,IE和Windows的許多安全漏洞,都在這些用戶的努力下被發現并且被利用了。很多人當初會說“緩沖區溢出?這是根本不會發生的事,用戶怎么會在字符串后面加這么多亂七八糟的東西?!”。
4、Bug的數量和測試人員的工作效率有關么?和開發人員的工作績效有關么
阿亨:當然有關!我們會在以后的實踐中碰到這些問題。
阿超:有關,但是也不是太有關。一個極端的例子,如果一個開發人員寫的模塊沒有任何Bug,那測試人員的工作效率如何衡量?我們以后再說。
5、有錯不改
果凍:微軟的產品經過這么多版本的不斷完善,應該是把所有問題都搞定,“止于至善”了吧?
阿超:那也不一定,在非常有名的電子表格軟件Excel中,就有這樣一個Bug:Excel 的日期計算功能認為1900年是一個閏年,這是不對的,但是它愣是一直沒有改正這個錯誤。
眾人:真的?為什么屢教不改呢?
阿超:故事是這樣的,當時這類電子表格軟件的市場領頭羊是Lotus 1-2-3這一款軟件。它的日期計算功能有一個Bug,就是把1900 年當作閏年。 這類軟件在內部把日期保存為“從1900/1/1 到當前日期的天數”這樣的一個整數。Excel 作為后來者,要支持 Lotus 1-2-3 的數據文件格式,這樣才能正確處理別的軟件產生的格式文件。這個錯誤就這么延續下來了,每一版本都有人報告,但是都沒有改正。我們可以在Excel 中試試看:
在任意格子(cell)中輸入“=DATE(1900,2,28)”,并且定義這個格子的格式為數字。大家可以看到數值變為:59。 表明1900/2/28 是1900/1/1開始的第59天。
輸入“=DATE(1900,2,29)”,可以看到 60! 這是一個不存在的日期!
輸入“=DATE(1900,3,1)”,數值是61,事實上,這應該是60。從這一天開始的所有日期都錯了一天。
果凍:還是可以抓住機遇,促成飛躍,在某一個版本徹底改好,不就是一個數字嘛。
阿超:改這個問題,技術上一點問題都沒有。但是在現實中會出現下列問題:
(1)幾乎所有現存文件的日期數據都要減少一天,所有依賴于日期的 Excel公式也要做檢查和修改。這在現實生活中是很難辦到的。
(2)Excel的日期問題解決了,但是其他軟件還是有這個Bug,數據文件在不同軟件中使用,就會有很頭痛的兼容性問題。
總之,這個問題就這樣一直留下來了。中間也有人想改過,你要注意看Excel 的 Options 設置,就會發現有這樣一個設置——使用1904年開始的日期計算系統 (use 1904 date system)(如圖7-1所示),但是一般的用戶誰沒事在這里打一個勾?
圖7-1