測試資料與參數化:一份腳本跑多組資料
#pytest #parametrize #測試資料 #QA 實戰
登入測試要驗正確帳號、錯誤密碼、空白欄位。三個情境,邏輯完全一樣,差的只是輸入和預期結果。把同一段腳本複製三次,下次登入頁改版,你就要改三個地方。pytest 的 parametrize 是正解:一份腳本,資料自己帶。 parametrize 基礎 用 @pytest.mark.parametrize 把資料和腳本分開,pytest 會自動展開成多個測試案例: 執行後 pytest 會顯示三筆獨立測試: test login[demo correct home title]、test login[demo wrong error msg]、test login[ error msg]。 哪組失敗一目了然,不用猜。 資料外部化 隨著情境增多,把資料硬寫在腳本裡會讓 parametrize 清單越來越長,而且測試資料和程式邏輯綁在一起:想多加一組測試資料,還得動程式碼。把資料改放 JSON,腳本只負責讀進來: 檔案 tests/data/login cases.json: 新增情境只改 login cases.json,腳本零修改。同樣的模式也適用 YAML:把 json.loads 換成 yaml.safe load 即可,結構不變。 帳號池:避免併發干擾 用 pytest xdist 開多個 worker 跑測試時,如果所有 worker 都用同一組帳號登入,後台 session 會互踢,測試互相干擾。解法是用 worker id 分帳號:xdist 給每個 worker 一個唯一 id(gw0、gw1……),依 id 的數字取帳號索引,每個 worker 自然拿到不同帳號,不需要跨程序同步。 注意:queue.Queue 是 in memory 物件,xdist 的每個 worker 是獨立的程序,各有自己的記憶體空間,不能共享同一個 Queue。 每個 worker 各自拿到不同帳號,同時跑多個測試也不會互踢 session。帳號數量對齊 n 的 worker 數即可;% len(ACCOUNTS) 確保 index 不越界,帳號比 worker 少時會輪流重複使用。 老實說:我的專案很少用 parametrize 上面的技巧都對。但在我自己的 App 自動化專案裡,parametrize 用得很少,大部分測試都是一支測試對應一個情境。 原因是 App 的流程很難套進同一個模板。登入的三種輸入可以參數化,因為流程一模一樣,只差資料。但 App 上大部分的測試不是這樣:買東西、領獎勵、切換設定,每一條流程走的畫面、要處理的彈窗、結束後要收的尾都不一樣。硬把它們塞進同一支參數化的測試,最後會在測試裡長出一堆 if,比分開寫更難讀。 我現在的判斷標準很簡單: 流程一樣、只差資料,才用 parametrize;流程不一樣,就老實分開寫 。這在 Web 表單驗證或 API 測試很常見,在 App 的 UI 層反而是少數。 那測試資料和帳號怎麼管 雖然很少用 parametrize,資料和帳號還是要管。我的做法是這幾條: 帳號跟著裝置走。 我不用 xdist 開多個 worker,所以上面那種依 worker id 分帳號的做法用不到。我的做法是每台裝置依 UDID 綁一組測試帳號,框架在測試開始時自動注入。同一台裝置永遠用同一組帳號,就算以後多台同時跑,也不會互踢。 使用者身分用 marker 標。 訪客、註冊會員、付費會員這些身分,我用 marker 標在各自的測試上,不用參數化跑同一支測試。不同身分能看到的畫面和能做的事差很多,流程本來就不一樣,分開寫比較清楚,要跑某一種身分的測試也只要用 m 篩選。 環境設定分檔。 測試環境和正式環境的設定各一份 yml,用環境變數決定讀哪一份。測試裡要知道現在是哪個環境,就從 pytest 的參數取,不寫死。 密鑰不進版控。 API key 這類東西,本機放在 .env(加進 .gitignore),CI 上放 GitHub 的 secrets。絕對不要寫進 pytest.ini,那個檔案是會被 commit 的。 還沒做好的:正式環境和測試環境的帳號隔離。 這條一直在我的待辦清單上。現在靠人記得哪組帳號是哪個環境的,這不是好做法,只是還沒排到。寫出來,是希望你在框架剛開始時就把它做掉,不要跟我一樣拖著。