本文主要首先主要介紹了什麼是自動化測試,接著對常用的自動化測試框架進行了對比分析,最後,介紹瞭如果將自動化測試框架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('https://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結合,並且實現自動化測試的定時執行,也是接下來需要繼續完成的內容~