第一次接觸”探索性測試“,是在三年前加入ThoughtWorks時的第一次QA社區活動上。同事妮子講了一個很長的PPT,細致地將所有的探索性測試方法羅列了一遍。我只覺得有趣,卻不完全記得住。但我了解到探索性測試的關鍵就是,打破常規套路,先去設計一部分測試,然后去執行,再基于執行的結果去發散一些新的測試思路。這不正是我平常的工作方式嗎?我為自己的”野路子“居然有如此良好的理論依據而暗自竊喜。
后來,我逐漸參與了很多敏捷項目,從簡單的單體應用到幾十個微服務交互的大型復雜系統,探索性測試的思路幫我一路升級打怪,我也對其逐漸有了更加深刻的認識。
“探索性測試(Exploratory Testing)”作為一個技術術語,是測試專家Cem Kaner博士于1983年提出的。有人稱其為一種”測試風格“、也有人稱之為”測試方法“、還有人將其等價于手工測試,但我更傾向于將其定義為一種”測試思路“。它區別于某一種具體的測試技術(等價類劃分、邊界值測試、自動化測試等),強調依據當前的上下文選擇合適的測試方法,因地制宜、避免南橘北枳。它可以用來幫助測試人員分析測試場景、制定測試策略、甚至指導自動化測試。
我們對”測試“常規的理解是,知道期待結果是什么,通過一些測試手段來驗證實際結果是否與期待一致。有點像小時候玩過的“蒙娜麗莎拼圖”:游戲的目標很明確,你只需要設計好拼圖的步驟,再按照步驟移動,然后就能夠看到著名的蒙娜麗莎的微笑。區別是,有經驗的玩家能夠做到以最快的速度、最少的步數完成拼圖,而初級玩家則需要較多代價。
傳統的測試方法是“先設計、再測試”。也就是說,先分析出測試點,然后針對測試點設計好測試用例,最后執行測試。這種方法在測試目標明確的情況下是可行的。然而在實際的項目中,我們面臨的測試活動要復雜的多。它更像是”打地鼠“游戲,總體目標是將冒出頭的地鼠給打回去,但你卻不知道下一秒,它的小腦袋將從哪個洞里探出來。
與傳統的測試方法相比,探索性測試 主張學習 ,強調 同時展開測試設計、執行、并從結果中獲得反饋,從而持續優化測試 。這是一種主張即興發揮、快速試驗、快速學習和動態調整的測試思維方式。這也是個迭代的過程,剛開始并不需要考慮地絕對充分,快速設計一些場景,然后從結果中獲得反饋,再進一步優化測試,從而使測試更加豐富。這與敏捷開發“小步迭代、快速反饋”的理念不謀而合。
就我看來,傳統測試與探索性測試并無好壞之分,反而相輔相成。傳統的測試方法強調有計劃地進行,而探索性測試旨在帶著使命在某個空間中漫游,但沒有預先設定的路線,從而發現更多沒有提前預見到的問題。
這幾年我參與了多個敏捷項目,我不斷嘗試學習和運用探索性測試,它不僅幫助我梳理測試策略,還能在測試過程中給予指導,對自動化測試的設計也起到至關重要的作用。
所謂測試策略,簡單來講,就是從”系統承載的業務“、”系統涉及的平臺“及”系統架構“三個角度出發,綜合解決”測什么“和”怎么測“的問題。
不同產品往往有不同的特征,如何合理的規劃和分解被測產品,就是在解決”測什么“的問題。
《探索性測試實踐之路》一書提到一種”漫游地圖模型“,它將測試比擬為游客在城市中漫游,幫助測試人員將被測產品劃分成不同的區域,再針對各個區域的特征,采取有針對性的測試方案。
如上圖所示,對于游客,旅游攻略幫助游客了解一個城市什么地方值得去、什么地方不值得去。那么,對于測試人員,可以運用”漫游地圖模型“將軟件從邏輯上進行劃分:
商業區:用戶花錢買軟件就是因為軟件的特性使得他們的業務得以完成。商業區測試類型著重于測試軟件的主要特性,因此,需要頻繁地進行回歸測試,以持續保證這些主要特性的可用性。由于具有很高的重復性,”商業區“的測試將是自動化測試關注的重點。
旅游區:對于軟件,有些特性對新用戶更有吸引力。這一點也涉及到部分用戶權限的測試。
歷史區:軟件也一樣具有前版本的歷史遺留代碼,這個區域的測試目的就是測試遺留代碼和遺留缺陷。這一點在遺留系統改造項目中體現的尤為明顯。”新開發特性不影響原有特性”將成為測試重點。
旅館區:當軟件“休息”時,它實際上還是非常忙碌的。旅館區模型關注的是一些輔助功能,比如軟件后臺運行等。
娛樂區:對于軟件,比如一個購物網站,商業區是搜索商品、加入購物車、生成訂單、付款等,而其娛樂區就是指漂亮美觀的UI、友好的用戶界面等。這就需要關注到用戶體驗和兼容性測試。
破舊區:不同于旅游,軟件的破舊區可能存在嚴重的缺陷、安全及性能問題。這部分可能是軟件的重災區,需要關注異常測試、性能測試和安全測試。
至于“怎么測”,每個項目實際情況都不太一樣,項目的各個階段也不盡相同。我們要依據當前的實際情況,運用測試分層理論、進行測試設計、做好工具選型。更重要的是,要根據測試執行給予的反饋及時調整策略、把控風險。
在敏捷開發中,我們以小步迭代的方式逐步完成產品的研發。舉個例子:我們在開發一個小型系統,該系統包含4個Feature(功能特性),每個Feature又被分解為若干個Story(用戶故事),每個Story就是系統中最小的業務單元。
其中,Feature 1中的Story A和B相互交互;Feature 1中的Story E與Feature 2中的Story K相互依賴;Feature 2中的Story I與Fature 3中的Story N相互關聯;Feature 3中的Story L與Fature 4中的Story R相互依賴。
假設按照產品計劃,我們即將在4個迭代中完成開發,每兩個迭代完成一次版本發布(Release)。那么,按照需求優先級、需求依賴關系、團隊速率等因素,story被合理的安排到迭代1至迭代4,如下圖所示。
那么我們如何有效地運用探索性測試來幫助我們實施測試呢?
探索性測試中提到三種常見的測試方法: 單個特性測試、交互特性測試 、以及 系統交互測試 。運用到敏捷開發中是這樣的:
首先,由于每個Story為最小業務單元,每個Story都需要在當前迭代獨立完成測試,這就是所謂的 單個特性測試 ;
其次,由于部分Story之間有依賴關系,比如迭代1中的Story A和Story B、當A和B獨立完成測試之后,我們要關注這兩個Story之間交互的測試。一個典型例子就是,A為某個頁面的UI、B為后端實現。測試Story A時,我們關心前端展示、校驗、交互等;測試Story B時,很可能A還沒有完成開發,我們需要通過API測試,人為地通過控制入參來完成后端邏輯的驗證。然而,我們如何保證前端在與后端交互時,傳遞給后端的入參是正確的呢?對于開發同學來說,“聯調”就是在解決這個問題,對于測試人員,這便是最小 交互特性測試 。
再者,通過迭代1和迭代2,我們基本完成了Feature 1和Feature 2的所有story的開發和測試,可以完成第一次Release啦。在Release之前,我們需要完成一輪回歸測試,測試范圍為Feature 1和Feature 2。假設Feature 1為“注冊”、Feature 2為“登錄”,我們已經分別完成了注冊和登錄功能的驗收,但是“新注冊的賬號是否能夠正常登錄”并沒有完全得到驗證。這就是 交互特性測試 ,旨在發現特性在各個特性在交互時的潛在缺陷。
然后,在迭代3中,Story N與已經發布在生產環境的Story I發生關聯,為了更好地是適配,很有可能Story N的需要被重構。那么我們在測試Story I時,要同同時關注與Story N的交互。
最后,在迭代4以后,我們完成了全部4個Feature的開發和測試,又要進行一次上線發布啦。同樣,在上線之前,我們又要進行一輪回歸測試。不過這次的回歸測試范圍不僅包括迭代3和迭代4新開發的內容,還要包含之前所有已經發布在線上的特性,也就是截至目前整個系統的測試。這就是 系統交互測試 ,以便發現整個系統中各業務單元之間交互的潛在缺陷。
當然,這只是個比較理想的例子,在真正的敏捷開發中,我們不僅要關注功能的單點測試和回歸測試,還要關注性能、安全、及兼容性測試。但是無論哪種測試類型,測試范圍都是從“單個特性 – 交互特性 – 系統交互”逐漸演進的過程。
由于敏捷開發節奏快,幾乎每個迭代、每個版本都需要完成或大或小的回歸測試。系統演進得越來越大,回歸測試的量也與日俱增。而在敏捷全功能團隊中,往往是四五個Dev配備一名QA,就算是千手觀音,恐怕也很難純粹靠手工完成所有的回歸測試,那么自動化測試就該登臺亮相了。
在手工測試的過程中,也可以逐漸抽取出一些新的測試點補全到自動化測試當中,這將極大地提高測試效率。
在敏捷開發中,我們運用測試金字塔的分層思想來制定自動化測試策略:
無論什么樣的自動化測試,都需要設定特定的輸入,有明確的輸出。但是敏捷開發是個演進式開發的過程,一些驗收條件在這個迭代是這個樣子,在下個迭代很可能就是截然不同的了;此外,我們對系統的理解也必將經歷一個逐漸深入的過程。因此,探索性測試中的一些方法正好可以幫我們彌補這個過程。
探索性測試方法有很多,這里對我幫助最大的是《探索式軟件測試》一書中定義的四個分類:
自由風格的探索性測試(Freestyle Exploratory Testing)對一個應用程序以任意次序和方法進行隨機測試,不提前設定測試范圍和規則,也無需大量準備工作。
在上面我們提到,冒煙測試是從E2E測試中提取的基本場景。但是,E2E測試實際上是整個測試中最困難的,它很大程度的依賴于環境,而一個完整的環境的創建與維護可能需要花費很大的精力,特別是當有多個不同的團隊在獨立開發時。因此,當自動化冒煙測試無法進行時,我們就可以通過這種自由風格的探索性測試來指導手工冒煙測試,以快速驗證軟件包是否存在重大崩潰或嚴重缺陷。
基于場景的探索性測試(Scenario-based exploratory testing)和傳統的測試方法有些類似,要有明確的測試的起點和終點。比如在E2E測試中,它可能基于基于user journal、用戶故事、程序的生命周期等。不同的是,它不限制路線。好比我們設定的場景是,從西安到北京,但并不限制出行方式和路線,你可以乘坐汽車、高鐵、飛機,你甚至可以繞地球一圈,只要最終能夠到達。
基于策略的探索性測試(Strategy-based exploratory testing)是指將自由式探索與經驗、方法、技能和第六感結合,它屬于但不完全等同于自由式探索,它是在經驗和技能的指導下完成,比較適合有經驗的玩家。
已有的測試策略是基于測試策略的探索性測試成功的關鍵,測試人員的測試知識和經驗越豐富,測試效率就會越高、效果越好。測試新人可以從測試老手的測試路徑中學習和提取一些新的測試場景,補充到自動化測試中。
基于反饋的探索性測試(Feedback-based exploratory testing)是指測試人員基于”上一次“或”上一條“測試的結果來動態調整自己的測試。
舉個例子,你由于肚子疼去醫院檢查,大夫輕輕按你壓腹部某個部位,如果你沒有反應,他會試著調整部位;如果你輕微”啊“一聲,大夫便知道這個部位存在嫌疑,他很可能會再按一次,并且力道稍大一些。”啊“一聲就是你給予大夫本次測試的反饋。
再舉個例子,團建的時候,大家常常玩一個”猜數字游戲“。法官在紙上寫下一個0-100的數字,由剩余的人從左往右依次猜數字,猜中的人將作為”幸運兒“接受懲罰。這完全符合基于反饋的探索性測試。
Case 1:第一個人猜”66“,法官回答”大了“。
那么第二個人便推測這個數字位于0-66之間。于是他調整自己的數字。
Case 2:第二個人猜”63“,法官回答”小了“。
那么測試范圍就被縮小到64-66之間,很顯然,答案就在64和65當中,那么第三位或第四位將會是那個”中獎“的人,最精彩的部分也就來了。
測試中我們也常常碰到類似的情況,一開始我們并不知道期待結果具體應該是什么,因此無法通過自動化腳本來完成測試。所以我們按照自己的經驗或推測先進行一組測試、再通過測試結果分析和設定下一組測試,依次循環直到找到最終結。等到所有的步驟和結果明確之后,就可以通過自動化腳本去完成了。
最后,由于探索性測試只是一種思路,并不是特定的測試方法,在實際運用起來并沒有固定的套路,每個人也對它有不同的理解。但希望我們在完成測試工作的同時,能夠時不時停下來總結和思考,從而使得測試更完善、也更高效。
原文轉自:https://insights.thoughtworks.cn/exploratory-testing-in-agile/