Web前端自動化測試Cypress實踐總結
- 2021 年 6 月 4 日
- 筆記
本文主要首先主要介紹了什麼是自動化測試,接著對常用的自動化測試框架進行了對比分析,最後,介紹了如果將自動化測試框架Cypress運用在項目中。
一、自動化測試概述
為了保障軟體品質,並減少重複性的測試工作,自動化測試已經被廣泛運用。在開始學習自動化測試之前,我們很有必要先搞清楚這幾個問題,什麼是自動化測試?為什麼要做自動化測試?哪些項目適合做自動化測試?
1、什麼是自動化測試
自動化測試是一種測試方法,是指使用特定的軟體,去控制測試流程,並比較實際結果與預期結果之間的差異。通過將測試自動化,可以把人對軟體的測試行為轉化為由機器自動執行測試的行為,從而替代大量的手工測試操作,使得測試可以快速,反覆的進行。
關於自動化測試,有一個測試金字塔模型,該模型把測試從下到上分為了單元測試、集成測試和端到端測試(E2E測試/UI介面測試)。越往金字塔底層,測試成本越低,效率也越高,而越往金字塔的頂層,測試成本會逐漸增高,收益也會越低。
- 單元測試
單元測試又稱為模組測試,主要針對程式中最小可測試單元(一般指方法,類)的測試,具備投入小、收益產出高的特徵,可以較早期地發現程式碼缺陷,適用於公共函數庫的測試。
- 集成測試
集成測試主要包括模組介面測試,子功能模組集成起來的功能模組測試等,目的是為了驗證在單元測試的基礎上,所有模組集成起來的子系統、子功能是否仍然滿足品質目標。
- 端到端測試
端到端測試的主要目的是從軟體使用者角度來檢驗軟體的品質,如打開瀏覽器,進行一系列的操作,驗證介面或功能是否符合預期。
不同類型的項目,具有不同的測試場景,因此也需要採用不同的測試類型。對於開發人員來說,單元測試專註於程式碼底層,可能是一種比較友好的選擇。但是站在產品的角度上,也許端到端測試(E2E)是更好的選擇,更能保障產品功能符合預期。
講完了自動化測試類型,我們再來看看測試中常用的測試模式,一般常用的測試模式包括TDD和BDD兩種。
- TDD
TDD(測試驅動開發,Test Driven Development),TDD是指先寫測試用例程式碼,再寫功能程式碼,並且不斷的重複上述步驟直到完成開發工作。TDD一般結合單元測試使用,是白盒測試。
- BDD
BDD(行為驅動開發,Behavior Driven Development),BDD是指先寫功能程式碼,再寫測試用例程式碼,BDD一般結合集成測試或端到端測試使用,是黑盒測試。
當然,是選擇TDD還是BDD,也是需要從項目的實際角度出發考慮,再做選擇。
2、為什麼要做自動化測試
接下來,我們再來聊聊為什麼要做自動化測試?在實際的項目開發中,我們常常會遇到以下問題:
- 產品迭代頻繁
迭代過程中不可避免的需要新增功能或修改功能,怎麼保障新功能的發布不會影響原有功能呢?
- 多人共同參與開發,程式碼維護難
項目開發過程中多人參與開發,人員變動頻繁,開發過程中可能出現誤刪或誤改他人程式碼邏輯的問題,如何保障程式碼的品質和可靠性?
- 測試人力不足,回歸測試耗時耗力
為了解決上面提到的兩個問題,其實方法很簡單,就是每次新功能發布後,都對原有功能再進行回歸測試。但是又可能遇到測試人力不足的情況,自己手動進行回歸測試又耗時耗力,如何才能減少重複性工作,提高效率呢?說到這裡,自動化測試就派上用場啦~
那項目引入自動化測試有什麼好處呢?自動化測試的好處主要包括了以下幾點。
- 驗證程式碼正確性,保障產品品質
可以驗證程式碼或產品功能的正確性,確保每次產品迭代,新功能和原有功能能夠正確集成,保證產品品質。
- 提高測試效率
編寫的測試用例具有一次編寫,多次運行的特點,通過執行測試腳本,可以實現使得測試快速,反覆的進行,可以替代大量的重複性手動測試工作,提高效率。
- 起到文檔作用
編寫的測試用例可以起到文檔的作用,有利於項目後續的維護。
3、哪些項目適合引入自動化測試
既然自動化測試有這麼多好處,那是不是所有項目都適合引入自動化測試呢?當然不是!自動化測試需要進行測試用例的編寫,需要一定的開發成本,我們需要立足於項目本身,再來決定是否適合引入自動化測試。
- 適合引入自動化測試的項目
1)產品周期較長,需要不斷進行迭代/重構的項目。2)公共庫類的開發維護。
- 不適合引入自動化測試的項目
1)產品周期過短的項目。2)需求變動過於頻繁的項目。
二、前端自動化測試框架選擇
在明確了我們的項目有必要引入自動化測試之後,就需要選擇一款自動化測試框架或工具來幫助我們完成自動化測試工作啦~
1、測試框架對比
下面主要對比了現在常用的Web前端自動化測試框架,如果需要了解更多的框架,可以參考測試框架選型
Jest | Mocha | Selenium/WebDriver | Nightwatch | TestCafe | Cypress | |
支援測試類型 | 單元測試 | 單元測試 | E2E測試 | E2E測試、Node.js單元和集成測試 | E2E測試 | 單元測試、集成測試、E2E測試 |
支援語言 | JS、Node | JS、Node | Java、Python、C#、JS | JS、Node | JS、TypeScript | JS |
是否支援可視化測試 | 否 | 否 | 否 | 否 | 否 | 是 |
是否自帶斷言庫 | 是 | 否 | 否 | 是 | 否 | 是 |
是否開箱即用 | 是 | 否 | 否 | 是(安裝配置繁瑣) | 是 | 是 |
錄製生成腳本 | / | / | 支援 | 不支援 | 不支援 | 不支援 |
Github Star | 35.2k | 20.5k | 20.8k | 10.7k | 8.9k | 31.3k |
文檔 | Jest文檔 | Mocha文檔 | Selenium文檔 | Nightwatch文檔 | Testcafe文檔 | Cypress文檔 |
在上述框架中,由於Cypress能夠同時支援單元測試、集成測試和E2E測試,提供了一套完成的測試解決方案,能夠滿足我們的需求。此外,Cypress支援JS編寫測試用例,支援Jquery元素定位選擇器,支援Headless和CI持續集成,運行速度快,上手成本低,並且具有可視化調試介面,方便定位問題。因此決定嘗試將Cypress運用到項目中。
三、Cypress實踐
接下來,主要介紹如何將Cypress運用在項目中。
1、Cypress安裝
在安裝Cypress時,可以直接在原有的項目上進行安裝,也可以另起一個項目安裝。
npm install cypress --save-dev
2、Cypress啟動
Cypress主要包含以下兩種啟動方式:
1)命令行執行npx cypress open:會在瀏覽器打開測試用例集的介面,需要手動運行。
2)命令行執行npx cypress run:會以無頭瀏覽器模式運行指定的所有測試用例,沒有可視化介面,但運行過程中會錄製整個測試過程的影片,可在cypress/videos目錄下查看。
當然,除了直接在命令行運行上述命令,也可以通過配置package.json的scripts欄位來定義啟動方式。
"scripts": { "serve": "vue-cli-service serve", "build": "vue-cli-service build", "lint": "vue-cli-service lint", "cypress:open": "npx cypress open", "cypress:run": "npx cypress run" }
- 可視化介面運行
如果我們需要在可視化介面進行測試,在配置好package.json後,只需要執行npm run cypress:open,就可以啟動Cypress,實現可視化調試,如果在啟動的過程中遇到以下錯誤,可以先執行npx cypress install -force,再重新啟動Cypress。
如果成功啟動Cypress,將會看到以下介面,examples目錄下是cypress自帶的測試用例演示程式碼(如果後面不需要,我們可以將這些測試用例刪除),點擊其中的某個測試用例,將會自動打開瀏覽器運行測試用例。
如果我們是第一次啟動Cypress,會發現在項目根目錄下也自動生成了cypress.json配置文件和cypress目錄。其中,integration文件夾就是我們用來存放測試用例的目錄,可以在cypress.json中自定義這些默認目錄的命名。
-
無頭瀏覽器模式運行
如果我們想以無頭瀏覽器模式運行,在配置好package.json後,需要執行npm run cypress:run,Cypress就會以無頭瀏覽器的模式運行指定的所有測試用例。
3、編寫測試用例
接下來以驗證百度頁面的搜索功能為例,演示如何編寫測試用例,測試用例可以以.spec.js或.js結尾命名,並放入cypress/integration中。
項目目錄如下所示,在cypress/integration中創建test.js或test.spec.js測試用例文件。
接著,可以在test.js中開始編寫測試用例,Cypress支援Jquery元素選擇器及漢字選擇器,並且也支援鏈式操作,此外,由於Cypress擁有自動等待機制,我們無須在測試中添加wait或sleep,Cypress會自動等待元素至可操作狀態時才執行命令或斷言。
/// <reference types="cypress" /> context('百度頁面測試', () => { it('訪問百度頁面,驗證搜索功能', () => { cy.visit('//www.baidu.com').then(() => { // 1. 輸入搜索內容 cy.get(".s_ipt").should("exist").type("Cypress自動化測試"); // 2. 點擊百度一下按鈕 cy.get(".s_btn").contains("百度一下").should("exist").click(); // 3. 驗證搜索內容不為空 cy.get("#content_left").find("div").then(ele => { expect(ele.length).gt(0); }); }); }); });
編寫完上述程式碼,我們就可以直接啟動Cypress運行啦,當然,我們也可以根據實際需要在cypress.json進行一些配置,下面給出了一些常用的配置,可以在Cypress文檔查看更多配置。
最後,執行npm run cypress:open啟動Cypress,啟動成功後,我們就可以看到以下介面,點擊test.js,就會在瀏覽器中運行該測試用例。
在測試用例執行的過程中,每一步操作都會被記錄下來,可以點擊左邊的介面對每一步的操作進行回看,可以幫助我們快速定位問題。
4、Cypess文件上傳/下載
在實際的使用過程中,我們通常也需要驗證文件上傳或下載功能,而Cypress也能夠滿足這些需求。
1)文件上傳
首先需要安裝cypress-upload-file插件。
npm install cypress-upload-file --save-dev
將要上傳的文件放到cypress/fixtures中。
編寫測試用例程式碼。
/// <reference types="cypress" /> context('文件上傳', () => { it('驗證文件上傳功能', () => { // 訪問頁面,此處步驟省略 let file = "file/cover.jpg"; cy.get("input[type='file']").attachFile(file); // 執行斷言,此處步驟省略 }); });
2)文件下載
若我們在運行測試用例的過程中存在文件下載操作,Cypress會自動在cypress目錄下創建一個downloads目錄,所下載的文件會自動保存在該目錄中。
可以在測試用例中讀取並解析下載的文件。
/// <reference types="cypress" /> const path = require("path"); context('文件下載', () => { it('驗證文件下載功能', () => { // 訪問頁面,執行下載操作,此處步驟省略 const downloadsFolder = Cypress.config("downloadsFolder"); const downloadedFilename = path.join(downloadsFolder, "下載文件.xls"); // 讀取文件 cy.readFile(downloadedFilename).then(data => { // 執行斷言,此處步驟省略 }); }); });
5、Cypress測試報告
在執行完自動化測試後,我們通常都希望能夠得到一份詳細的測試報告,而Cypress也能夠提供這個功能。Cypress除了內置的測試報告,也支援用戶自定義報告格式。
1)內置的測試報告
Cypress內置的測試報告主要包括了spec格式報告(在控制台窗口輸出嵌套分級視圖),json格式報告(在控制台窗口輸出一個大的json對象)和junit格式報告(輸出一個xml文件)。以spec格式報告為例,在啟動cypress時加上以下參數即可。
2)自定義的測試報告
常用的自定義測試報告有Mochawesome報告,Mochawesome是與Mocha一起使用的自定義報告程式,並與mochawesome-report-generator結合使用以生成獨立的HTML/CSS報告。
安裝mocha和mochawesome。
npm install mocha --save-dev
npm install mochawesome --save-dev
修改啟動參數。
運行npm run cypress:run,執行結束後,會在項目根目錄下生成mochawesome-report目錄。
在瀏覽器中打開mochawesome.html,就可以查看可視化測試報告。
四、編寫可維護的測試腳本
在實際編寫測試用例的過程中,隨著頁面的增多,我們常常會遇到以下這些問題,而這個時候,如何編寫可維護的測試腳本,方便後期維護,也顯得非常重要,這裡也總結了實際開發中的一些經驗。
1、測試用例程式碼結構組織
在編寫測試用例時,我們可以一個頁面對應一個測試文件,也可以同個功能模組的頁面一起對應一個測試文件,並且和平時開發中所採用的程式碼組織結構類似,將不同的測試文件劃分到對應的目錄下進行管理,方便後期的維護。
2、頁面選擇器統一管理
在E2E測試中,我們通常需要獲取頁面元素,才能夠進行點擊等操作。而Cypress支援Jquery選擇器,我們可以通過元素的class或id定位元素。但是一旦頁面的類名或id發生變化,我們不得不修改對應頁面的所有測試用例。
在編寫測試用例的過程中,我們可以將頁面選擇器進行統一管理,實現類名或id選擇器和邏輯程式碼的分離。對於每個頁面或者每個測試文件,可以創建一個對應的xxxControl.js文件,在該文件中,將會定義一個json對象並且export出來,其中,key為我們自己定義的選擇器名稱,而value值對應頁面中實際的class或id。
由於目前項目中使用到了iview組件庫,因此也提取出了commonControl.js,對iview的選擇器進行統一管理。
由於每個頁面都採用到了iview組件,因此每個頁面或每個測試文件對應的control.js都需要將上面的commonControl.js引入進來。
最後,每個測試文件只需要引入對應的control.js,就可以通過自己定義的key值獲取頁面真正的class或id。
上面的方法看起來雖然麻煩了點,但是有兩個好處,首先,採用自己定義的key值,更容易方便我們記憶,可以減少編寫測試用例過程中反覆查看頁面元素對應的class或id名。其次,當頁面的類名或id發生變化時,我們只需要修改頁面對應的control.js文件就可以,而不用修改所有的測試用例文件,有利於後續的維護。
3、路徑名及介面統一管理
在編寫測試用例的過程中,我們通常需要使用cy.visit()去訪問某個頁面,或者使用cy.request()去調用後台介面以請求數據或創建測試數據,對於頁面url或後台介面api,我們也可以放入某個文件中進行統一管理。
4、程式碼復用
在測試的過程中,我們可能會注意到,不同的頁面可能會存在一些相同的功能。比如像目前的項目中,不同的頁面都需要對一些操作進行彈框確認或表單輸入,而在驗證彈框功能是否正確的過程中,我們都需要對彈框執行點擊確定按鈕、點擊取消按鈕、點擊關閉按鈕等操作,而這個時候就可以採用面向對象編程的方法實現程式碼的封裝和復用。
定義一個彈框類,並且定義屬性和方法。
在測試文件中,需要實例化對象,並調用相關的方法完成某個操作。
當然,有些方法並不是所有的頁面都共有的,但是在某個頁面或功能中會反覆使用到,因此也可以為每個頁面或每個測試文件單獨封裝相應的方法。比如為課程管理頁面封裝相應的通用方法。
以上就是關於將Cypress運用在項目中的一些總結,而如何將Cypress和CI/CD結合,並且實現自動化測試的定時執行,也是接下來需要繼續完成的內容~