Stages in Software Testing


這幾年 DevOps 盛行,大家都在討論,然後都在喊要 CI 、要自動化測試 ….

我從 Software Developer, Software QA (SQA), System Operation / Administrator 三種角色 / 職務都走過,做了幾年的 System Operation / Administrator 之後,最近開始有機會回到 Developer 身份,專注 Microservice 與架構,反思測試的重要性感覺又更深刻。

How to be an SQA? 有過去經驗的分享。

整理一下過去做 SQA Manager 時的 Test Strategies (測試執行策略) 與心得。

本文整理的資訊,大概只是 目錄基本章法,有空再把內容展開,整理出完整的分享。

名詞定義

先整理名詞定義:

  • Test Stages: 測試的階段性
    • 怎樣的測試階段,每的階段的目的性、範圍、確認點都不一樣。
    • 這些 Stage 有些事有相異性的,有些依照不同的產業、產品性質,則是屬於選擇性的。
    • Stage 種類很多,我的定義主要來自於 IBM 的測試方法。
  • Test Strategies: 策略
    • 依據不同產品特性,選擇不同 Stage 的組合,稱為策略 (Strategy)
    • 我心裡有一個基本款的策略,也就是不管是怎樣的產品,都要走完,否則就是不及格。
    • 最基本的 Test Strategy: Functional Test + Regression Test

我定義的測試全部都是黑箱,也就是不包含 Unit Test,因為那是 Developer 的責任。

摘要 Stages

有些名詞我是沿用 IBM 的體制,大概就是 xVF 之類的稱呼,只是定義是我自己的經驗匯集。

Unit Test (UT)

  • Developer 的職責,白箱測試。
  • 邊界驗證 (Boundary Test), dummy data
  • Developer 要專注在 Design, Coding, and Unit Test. (IBM 稱為 DCUT)
  • 容器技術的誕生,UT 更容易了,持續整合 CI 的實踐更加方便了。

Functional Verification Test (FVT)

  • 功能測試,也就是主要的商業功能與流程。這是一般做測試最基本的工作,也是 QC 的範疇。
  • 包含完整的 User Stories, Scenario, Use Cases
  • 這段落的測試 完成率 必須 100%, 通過率 必須 90% 以上,才能繼續往下走。
  • 完成率 以及 通過率 的比例與設定,因產品性質不同而有所不同。
  • FVT 測試環境的 Provisioning:
    • 環境建置專注在功能面 / 應用層,不是系統面
    • 不用考量 Performance 部分,像是 HA / Failover / Reliability 等,也不用去弄 DB HA / Replication
    • 測試環境要最小化,盡量使用 Container 技術,讓每個人 (Developer / QA) 都可以快速建立自己的環境。
    • 容器技術的誕生,FVT 更容易了。

Integration Test

  • 不同 商業功能 之間的互動性測試
  • 著重在 商務領域 的適用性,也就是走的是 User Scenario,必須包含 商業邏輯 + 場景條件
    • 商務邏輯: 打開 APP -> 點選 FB 登入 -> 確認註冊權限 -> 完成登入
    • 場景條件: iOS / Android / Web on Desktop / Web on Mobile …
  • End to End 可以說是一種 Integration Test
  • 有些產業會把 System 和 Integration 合在一起稱為 SIT,我覺得不太適合。
  • 環境建置考量:同 FVT 需求

System Verification Test (SVT)

  • 假設功能已經好了,通過 FVT / Integration Test,把它放到不同的系統,可能的影響。
  • 針對 系統性 的驗證,兩個異質性系統的溝通、配置、效能等問題。
  • 外在條件的影響,例如不同的瀏覽器、作業系統、版本、 … 等
    • iOS / Android 版本
    • Android 的型號 (xxoo)、Android 的 Resolution
  • 偏重在技術端、系統面的邏輯正確性與系統串接功能正確
  • 效能測試 (Performance Test) 也是系統測試的一種,分成很多種,後述。
  • 這些也歸類在 SVT:
    • Smoke Test / Monkey Test
    • Installation Test / Deployment Test
    • Pipeline Test (CI / CD)
    • Configuration Test (Config 是是要測試的)
    • Chaos Engineering
  • 環境的建置考量:
    • 仰賴 Resource Provisioning ,也就是環境建置自動化,相關技術有 AWS CloudFormation、Terraform ..
    • 要考慮完整的系統架構,包含 HA / Failover / Reliability / DB HA
    • 要確認這些系統環境彼此的 config / functional 正常能正常運作
    • 系統之間的設定問題,要在這階段找出來。
  • 上線後的監控指標 (Metrics):

更多參閱: 輕鬆聊:系統測試 (SVT) 的三兩事

Regression Test (RT)

  • 中文翻成 回歸測試
  • 把舊的功能全部都測過,理想 有包含以下幾個 Stage:
    • FVT
    • Integration Test
    • SVT
    • 測試曾經出現過的 嚴重 Bug
  • 高度仰賴自動化
  • 環境建置可以是 FVT or SVT 的條件。

經驗上,很難真的達到這樣的標準,我實際做過的大概是這樣分配:

  • 全部 FVT,包含所有 User Story
  • 少量 Integration Test
  • 少量 SVT
  • 大部分嚴重的 Bug

這樣可以滿足大部分的條件,也達到品質金鐘罩的目的。

案例討論:從 iOS 無限黑屏事件,淺談軟體測試階段 - 回歸測試 Regression Test

回歸測試的挑戰,如何面對 已知 Bug 的問題:

  1. 已知問題如何在測試環境重現,包含測試資料、系統配置的還原
  2. 測試程式與資料如何組織與管理
  3. 測試程式如何測試
  4. 測試程式執行的管理:同樣的步驟,可否同時跑不同的版本?

這邊部分的心得,請參考 SRE CH25 - Data Processing Pipelines, P15 的經驗分享。

Test Framework for Regression

單一的自動化測試難度不高,但是如果大量且要能夠團隊合作的 Test Framework 複雜度就很高,我設計過的 Test Framework 考慮以下:

  • 環境建置準備:
    • 把環境弄到最乾淨,以 AWS 來說就是起一個乾淨的 Instance
    • 用 Container 相關技術,像是 Docker-Compose、K8s …
  • 測試資料準備:
    • 每個 test case 都會有個別的測試資料,用來製造測試情境
    • 測試資料的分類
  • 待測程式的部署或者安裝:
    • 這些東西統稱 artifacts, 建議包含以下資訊:Version Number, Change ID (hash code, serial no), BuildID (通常是時間, 像是 YYYYmmDD-HHMM), branch … 詳細參閱 Version Control
    • 從 build machine or S3 抓下最新的 build,安裝好後,把 test case 需要用的設定檔設定好
  • 單一 Test case 的開發流程與流程控制: tester 寫 test case 如何在自己的環境開發與測試
  • Test Suite 的管理與結構: 如何跑整個 test suites,test suites 本身的設定檔
  • Runner 的設計:
    • 跑單一 testcase,
    • 跟跑數個 suites 的設定檔, 然後可以個別指定設定檔, 或者 overwrite 每個 testcase 的設定檔
  • 測試排程控制 (分散式):
    • 如何同時跑多個 test case?
    • 排隊或者平行?
    • test case runtime 在哪一台機器跑?
    • 如果 test case 跑太久怎麼辦?這裡我設計了 duration 機制,也就是 tester 必須指定每個 test case 最長的執行時間,超過 test runner 就會把 thread 砍掉,並且執行 cleanup,把環境還原,把測試標記失敗。
  • 模擬程式的設計:有些測試程式需要製造一些特殊條件,像是 disk 滿了、CPU 80%、memory 沒了之類的 …
    • 我設計由 Framework 提供這些功能,tester 只要透過參數就可以達到想要的功能即可。
  • 額外的測試條件 Callback: 跑大量 test suite 時,可以同時跑其他的東西製造測試情境
  • 測試結果的 Log 與報表
    • Log 分成給 tester 看得、Framework Library Design 看的,還有 Framework Developer 看得。
    • 每個 testcase 都有 owner, 報表每天會自動寄給 owner
  • Rerun 機制
    • 每次跑大量的 test suites 產生報表的同時,會同時產生另一個 runner 的設定檔,只要 reviewer 看過覺得需要重跑,按下 rerun 就可以自動化重跑
  • 資源監視
    • 待側機器的資源狀況,主要有 CPU / Memory / Disk 狀況
  • Test “Test Framework”:整個 Test Framework 自己的 Unit Test 以及 Libraries 都是透過自己測自己的方式實作,也就是自己的 Libraries 也會產生測試報表,每次加功能之前,都會用自己測自己 (當時我還不知道那叫 TDD)。這樣的想法是以前學 Java 時,聽學校老師說 Java Compiler 用什麼寫?當然是用 Java 寫囉!當時還不懂,後來就懂了。

下面是以前我設計 Test Framework for Regression 時規劃的流程與設計 (System Level Design),摘錄一些當時簡報的圖檔與心得:

程序的設計,有 Framework Level 和 User Level

測試程序的設計,有 Framework Level 和 User Level。Framework Level 根產品的特殊性有關係,產品相關的共用程序都封裝在 Framework 層,User Level 則是給 SQA 開發 Test Case 使用。

中間有一些 function,像是 Raise CPU, Memory Up,是由 Framework 控制。Tester 在開發 Test Case 時,只要指定參數就可以了。

Test Case 的目錄結構設計,參考 Java package 概念。

Test Cases / Test Suites 的目錄結構設計,參考 Java package 概念。而且 Suites 和 Test case 的設定檔具有繼承、annotation、branch 概念。branch 概念就是說屬於特定版本的設定,可以建立新的 設定檔,附加版本號碼,Framework 只要找到這樣的檔案,就會自動 overwrite 相關設定。

  • 類似 Branch 的概念,在 Ansible 裡也有。
  • 這裡我實作了一個簡單的 parser,parse 每個 testcase 設定檔的相關需求,包含繼承、annotation、branch 等概念,實作內容包含基本的 syntax check、abstract structure tree (AST) 等,如果 syntax error 會吐出 error code, 同時指出哪一行錯誤。最後在 runtime 變成一個 data model 給 test runner 使用。在 Talk about compiler and parser 有簡單的描述。

這張圖是更大的測試流程圖,包含準備、自動更新 Firmware、Sequence / Parallel 的 Test Case 執行程序、以及 Log and Report。

這是執行後給 Testcase owner 的測試報告,列出 owner 每個 test case 的執行結果與 Log.

這張圖是測試資源的管理,Framework 會依據資源狀況,自動分配 Job。用 ZK 實作的。

我在 軟體自動化測試常見的問題 中問題到的描述,就是這段實作過程的經歷。

這一整套 Test Framework 是設計給一個團隊使用,裡面包含了協作、資源系統、報告、教育訓練、完整的文件手冊、範例程式碼、設計文件 … 等,當時一直想把他商品化,可惜並沒有機會。 (老了,要開始提當年勇了 XD)

Migration Test

有幾種混合的情境:

  • 通常是新舊程式 (database) 合併之後的測試。
  • 不同 app 版本對 server side 的差異測試

Migration 是很複雜的事情,所以 Plan 很重要,特別是需要長時間的執行,沒規劃好的 溝通成本 會非常驚人。

更多參閱:相容性與維護性

Performance Test

分成幾種: Stability, Reliability, Stress/Load Test, Capacity

作 Performance Test 的前提:FVT、SVT 要過。

我做 SQA Manager 的時候,本來是要去做 Performance Test,但是發現功能根本就不能用,所以就整個砍掉重來,先把 FVT 守住,直到通過率到一定程度之後,才開始 Performance Test。這段故事在 協同合作系統建制與導入 - 以 Redmine 為例 有提到一點。

環境建置考量:必須跟 Production 一致,可以利用 Cloud (ex. AWS, GCP) 快速建立完整的 Scale,測完就刪掉。

Stability (穩定性)

一定的資源之下:長時間,且大量的 Request 之下,系統維持在穩定狀況,不會有 CPU / Memory 凸波、或者是 Memory Leak、Disk I/O 瞬間的狀況。

如果應用程式本身具備 GC 機制,當記憶體使用量到一定程度時,則會自動恢復。

現象:不倒翁

Reliability (可靠性)

  • 不論時間與條件的運作,如果系統任一元件或角色 Crash 狀況,恢復之後,所有的資料以及狀態都會恢復正常。
  • High Available (高可用性), Fault Tolerance (容錯), Resilience (彈性), Recoverability (可回復性), Loosely Coupled … 都是可靠性的實踐方法
  • Nexflix 提出的 Chaos Engineering 也算在這裡

更多參考:

Capacity (容量測試)

目的在 量測 (Measure) 系統可以乘載的數據,單位可以是線上使用者、單位時間內的交易量、單位時間內的流量 … 等,像是 QPS (Query Per Second)、RPS (Request Per Second) …

量測的對象就是整個系統,系統要考量以下:

  • 一定的硬體資源,包含 Networking, Computing, Memory, Storage .. 等條件,應用程式能夠滿足多少的處理單位。
  • 放在 AWS 上的網站來說,使用 c4.large 的機器,最大能夠乘載多少的 HTTP Request,這個值稱為 Benchmark.
  • 有了 Benchmark 可以根據需求推論出系統需要的成本。例如已經知道 c4.xlarge 可以同時乘載 5k/second request,,那麼就可以推論如果有 100k/s request 需要準備多少台 c4.xlarge
  • Rate Limit: 服務提供固定的 SLA,像是可以乘載的數量上限,超過時候,告訴 Client 已經滿了。這種設計應用在 搶購 (flash sales) 是必要的。

Performance 測試除了上述面向,另一個面向就是帶測體是屬於整個 stack,還是 layer or tier

例如傳統的 web 有三層: Web -> Application -> DB,每個 layer 都有自己效能的問題,最終的目標是了解整個 stack 的 benchmark,但實際在執行上應該要先 bottom up,也就是先找到每一個 layer 自身的效能,最後才能測出 stack 的效能。

另一個例子是 realtime stream,像是影音串流的效能,先不考慮使用 p2p 技術,考慮使用 server relay 技術,一班實作就是: data source -> server relay -> client (app or web)

這三個端點都各自有傳輸的延遲時間 latency,每個節點都有運算時間,所以效能就包含兩個議題:

  • Latency: 資料傳輸時間,相依於網路,WAN -> Gateway / LAN / NAT / Wi-Fi … 等節點
  • Computing: 每個節點 encode / decode 的運算、protocol (RTSP)、mjpg / h264 … 等

從 Stack 的效能測試屬於 Top-Down View,大部分都會直接用這種方式開始,特別是沒有很多資源的狀況之下。一開始入門效能測試也都會從這個角度著手的比較多。

從 Layer 則屬於 Bottom-Up 方法,先找到每個 Layer 的 Capacity,然後再用數學方法模擬出整個系統的樣子,最後用 Infra as Code 的方式建立整套的系統,模擬測試。

這些根系統架構會有直接關係,現代的常見的 Pattern 就是 API GatewayService Mesh

效能測試的準備工作

如果是測試 Web System ,那就要花時間把整個系統建置起來,準備好測試資料,餵到 DB … 等。

實際上不只是待測要花時間準備,測試的 Client 的準備也是要花不少時間的,例如:

  • 模擬商業邏輯的資料,像是 Database Schema or 模擬使用者資料的 資料 … (啥鬼XD)
  • 測試程式的設計,模擬功能的行為。以 Live Stream 就是模擬 IPCam 的資料丟到 Server 然後傳給 App。
  • 測試程式執行環境的準備,要確認網路 Throughput 是否足夠
    • 測試環境能否自動化建置,最好利用像是 AWS CloudFormation 這樣的東西
    • 平常就要做好 Resource Provisioning 的工作。
    • 用 AWS 的話,確認機器等級的 Network 狀況,透過 VPC Flow Log 蒐集狀況
  • 測試流程 (HTTP Request) 模擬與建制,可以從既有的 Log 分析
  • 測試過程要蒐集的資料與 Log, 如何觀測 (Observailitiy)?參閱 Monitoring vs Observability
  • 預期會產生的資料如何分析?

這段 AWS NLB 的介紹中:Deep Dive: New Network Load Balancer 提到效能測試,Client 開了 c4.xlarge * 100

User Acceptance Test (UAT)

使用者接受度測試,一句話:出貨前最後驗證,要驗證什麼?

產品最重要的功能,最常走的路徑,那些功能就是 UAT

Field Test

前述的 Stage 都不是在 Production 測試,只有 Field Test 是正式環境,根 UAT 唯一的差異就是 環境,UAT 是在內部的環境, Field Test 則是在 Production。

也可以稱為 Sandbox.

Deployment Test

部署測試。

現在講求自動化部屬,我常常會反思:請問你的部屬程式可以測試嗎?可以在 Local Workstation 搭配 Container 模擬部署流程?

現在有所謂 GitOps,強調概念就是 deployment pipeline 可以程式化,強調 Ops 的觀念,那 Ops 是什麼

其實,我想要強調的是:

  • 只要是 Code,就要能測
  • 自動化程式 也是程式
  • 部署 本身也是一個功能,只是它是服務軟體開發,他是軟體工程必要的一環。
  • CI / CD 產生的 Code 都要可以被測試,本身要有自己的測試,確保正確運作。

其他 xVT

除了前述提到的,以前在 IBM 還有 GVT (Globalization)、IVT (Installation)、TVT (Translation) … 等測試。

除了這種 xVT,還有最近流行的 CI / CD / Deployment 其實也都是要測試的。

其他領域

硬體生產領域也有類似的階段,主要的 DVT, EVT, PVT 三個階段。請參閱 Introduction to Embedded Systems 的介紹。

Strategies 策略

依據產品性質、專案執行的資源、時程、市場需求,會有不同的策略。策略由不同 Stage 組成,理想的條件,全部都要有,不過那是理想。最基本的組合,也是很常見的組合,就是沒有測試就出貨了,嗯,沒有 QA 團隊的公司都是這個等級。

我認為,不能跟老闆妥協的,最基本的有兩個:FVT + RT,這是要守住的基本底線。依照專案資源、時間狀況,過去我會搭配,有時候會搭 (FVT + SVT) + Migration + RT

FVT 我會直接跟 SVT 混著一起跑,Test case 直接設計成 E2E 就可以做到類似的,節省資源與時間。但前提是測試人員除了瞭解商業邏輯,同時也要懂系統架構,甚至是 Provisioning。

這些 Stages 大部分的公司都不會有,要使用也要看公司的規模,或者發展階段。剛開始燒錢的時候,只要有 FVT 就好,甚至是 Developer 自己來。但是到跨國組識,這些每個 Stage 可能都是一個 Team 的等級。

不同階段的企業

CI: Continuous Integration

CI 有幾件事一定要有才算:

  • Build, Artifacts
  • Bind Build Information
  • Unit Test (Automatic)
  • Code Quality and Analysis

實際上要做到完整的不容易,有很多基礎建設要做。

相關概念參閱: Study Notes - CodeDeploy Preparation 第一段說明。

Resource Provisioning and Test

前述很多 Stages,不管哪一個都需要在正確的測試環境執行,換言之,錯誤的環境,會造成嚴重的資源浪費與狀況誤判。

Resource Provisioning 是測試的第一件重要事情,也是 DevOps 的第一件要事。實踐方法很多,可以使用 Container 技術,也可以用 Infra as Code 的方法。

建立測試環境還有一個很重要的目的,經常 review 現在整個系統的 Interface。系統之間的 Component 透過什麼方式串接?有多少 Endpoint?使用了哪一些第三方的 API Endpoint?Key?SSO?如果要建立一套新的系統需要先準備哪一些東西?那些東西好準備嗎?有 test 模式?像是信用卡測試帳號。

如果有經常做系統安裝以及 Review,基本上這些應該不是問題。Manager / PM 應該要清楚掌握這些東西,然後主動對外要資源。避免測試過程因為這些資訊不正確,造成測試結果不正確。

我在擔任 SQA Manager 基本上很少出現這問題,因為開測之前就會全部 ready。

詳細參閱:Resource Provisioning and DevOps

我把『環境建置速度與完整性』當成是軟體開發流程成熟度的指標。

環境建置完整性 = 具備可測性 = 品質的 Baseline = 清楚的架構
環境建置的速度 = 快速交付與驗證 = 自動化測試的基礎

在一個沒有清楚 Baseline 測出來的結果,我都是打問號的。

結論

測試應該是整個開發週期最長的時間,因為他需要把所有路徑都走過,把所有狀況都模擬過。

我的腦海裡常常有這樣的畫面:一個戰場上的戰士,還沒上戰場之前,有過嚴格的訓練,上戰場前就已經是傷痕累累,已經是經百戰。測試,就是上戰場前的準備。寧可多測,也不要隨意 Release。軟體的問題通常會是非線性的關係,覆水將難收,已經上戰場了,才來磨槍,只會死得更慘。

我從不相信『臨陣磨槍,不亮也光』這種屁話。

用吉他來說,測試就是一種練習,把每個音階、和弦、技巧練熟悉,一首歌練一百次算很少、一千次算可以上台表演。軟體也是,Release 之前能夠經過千錘百鍊,才會有品質。

有朋友問,為什麼要分這麼多 Stage?測試有那麼複雜?實際上就是那麼複雜。這篇文章,對我來講應該只是目錄,每個 Stage 有時間我再獨立說明其中的原委以及我自身經歷的故事。

XXX is Dead 這幾年很常出現這種話,像是 Test is Dead, Ops is Dead … 這些幹話,我覺得看看就好,認真就輸了。因為通常會說出這種話的,實際上都沒做過那件事事情,了不起只是沾醬油而已。

品質從需求就開始了,測試只是一種手段。

延伸閱讀 (站內)

測試

流程 & 管理

Operations

參考資料 (站外)


Comments