3 Cypress 測試框架概述
3.1 Cypress 默認文件結構
在Cypress安裝完成後,其生成的默認文件目錄如下所示:
3.1.1 Fixtures
Fixture又稱之爲測試夾具,通常配合cy.fixture命令使用,主要用於存儲測試用例的外部靜態數據。其默認位置位於cypress\fixtures中,也可以根據需要配置到其他目錄。 Fixtures裏面的靜態數據通常存儲在json文件中,而這部分數據通常是某個網絡請求對應的響應部分,如HTTP狀態碼和返回值等。Fixture的應用場景通常爲,當測試需要對某些外部接口進行訪問並依賴於其返回值時,可以使用fixture而無需訪問這些接口。
3.1.2 測試文件
測試文件就是對應的測試用例,一般位於cypress\integration中,也可以根據需要配置到另一個目錄中,通常爲js文件,在Cypress中其他命令格式爲:fileName.spec.js,支持的文件類型如下所示:
- .js
- .jsx
- .coffee
- .cjsx
3.1.3 Plugins
在Cypress中,測試代碼是運行瀏覽器裏面,提供了更加可靠的測試體驗,但也存在明顯的缺點,使得與瀏覽器之外進行通信更加困難。爲解決這個問題,Cypress提供了一些插件,可以修改或擴展Cypress的內部行爲。插件一般位於cypress\plugins,在每個測試文件運行之前,Cypress會自動加載該目錄中的index.js文件。
3.1.4 Support
支持文件一般位於目錄cypress\support中,可以根據需要放置在其他目錄中,其主要功能是放置可複用配置項,如底層通用方法、全局默認配置等。在每個測試文件運行前,Cypress會自動加載該目錄中的index.js文件。
使用方法也非常簡單,僅需要在cypress\support\index.js文件中添加beforeEach()函數即可。示例如下所示:
beforeEach( function (){
cy.log(`Current Enviroment is ${JSON.stringfy(Cypress.env())}`)
}
)
3.2 核心概念
3.2.1 核心參數配置
在第一次打開Cypress Test Runner後,cypress.json將會創建,目錄與Cypress同級。該文件主要用於保存所有支持的自定義配置,在配置了錄製和測試項目後,則projectId將會被保存至cypress.json文件中。
用戶可以通過參數來定義所使用的配置文件,參數爲--config-file
3.2.1.1 全局配置項
以下爲Cypress支持的常用自定義的全局配置及其默認值,如下所示:
配置項 | 默認值 | 描述 |
---|---|---|
baseUrl | null | URL前綴,通常與命令cy.visit()/cy.request()結合使用 |
clientCertificates | [] | 客戶端證書選項數組 |
env | {} | 環境變量設置選項,任何支持的值均可 |
numTestsKeptInMemory | 50 | 在內存中保存的快照和命令數據等數量,在運行測試時,若內存佔用太高,可以減少該值 |
port | null | Cypress使用的端口號,默認隨機產生 |
redirectionLimit | 20 | 在出現錯誤前,允許應用程序在測試運行時重定向的數量 |
reporter | spec | 在Cypress運行時使用的的reporter |
reporterOptions | null | reporter支持的配置選項 |
watchForFileChanges | true | 用於監測文件變化,若有變化,則自動重新運行該用例 |
3.2.1.2 超時
超時是Cypress中的核心概念,所以必須瞭解,常見的超時參數如下所示:
配置項 | 默認值 | 描述 |
---|---|---|
defaultCommandTimeout | 4000 | 命令默認超時時間,單位爲ms |
execTimeout | 60000 | 在cy.exec()執行期間,等待系統命令完成執行的超時時間,單位爲ms |
taskTimeout | 60000 | 在cy.task()執行期間,等待任務完成執行的超時時間,單位爲ms |
pageLoadTimeout | 60000 | 在等待頁面加載或cy.visit()/cy.go()/cy.reload()等命令觸發其他頁面加載事件的超時時間,單位爲ms,網絡請求受限於操作系統 |
requestTimeout | 5000 | 在執行cy.wait()命令時,請求超時時間,單位爲ms |
responseTimeout | 30000 | 在執行命令cy.request()/cy.wait()/cy.fixture()/cy.getCookie()/cy.getCookies()/cy.setCookie()/ cy.clearCookie()/ cy.clearCookies/cy.screenshot()時的響應超時時間,單位爲ms |
slowTestThreshold | 10000 | 250 | 在Cypress run期間,運行較慢的測試用例在reporter中將會以桔黃色顯示,通過該參數可進行單獨設置E2E和組件測試超時時間,E2E默認超時時間爲 10000ms,而組件測試爲250ms,單位爲ms |
3.2.1.3 目錄和文件
Cypress支持自定義目錄和文件,如下所示:
配置項 | 默認值 | 描述 |
---|---|---|
downloadsFolder | cypress/downloads | 在測試期間,默認的文件下載目錄 |
fileServerFolder | root project folder | 向服務器發送的應用程序文件目錄 |
fixturesFolder | cypress/fixtures | fixture默認目錄,可更改默認值爲false來禁用 |
ignoreTestFiles | *.hot-update.js | 在運行期間,需要忽略的測試用例 |
integrationFolder | cypress/integration | 測試用例所在目錄 |
pluginsFile | cypress/plugins/index.js | Plugins所在目錄,可更改默認值爲false來禁用 |
screenshotsFolder | cypress/screenshots | 在測試用例運行失敗或cy.screenshot()命令觸發截圖,用於保存這些截圖的目錄 |
supportFile | cypress/support/index.js | 在測試加載之前要加載的文件 |
testFiles | **/. | 要加載的測試文件 |
videosFolder | cypress/videos | 在Cypress run運行期間,用於保存video的目錄 |
3.2.1.4 截圖
配置項 | 默認值 | 描述 |
---|---|---|
screenshotOnRunFailure | true | 測試用例運行失敗後將進行截圖 |
screenshotsFolder | cypress/screenshots | 在測試用例運行失敗或cy.screenshot()命令觸發截圖,用於保存這些截圖的目錄 |
3.2.1.5 視頻
配置項 | 默認值 | 描述 |
---|---|---|
videoCompression | 32 | 設置視頻的壓縮比,設置爲false關閉壓縮或0~51,數字越低,視頻質量越好,文件越大 |
videosFolder | cypress/videos | 在Cypress run運行期間,用於保存video的目錄 |
video | true | 是否啓用視頻功能 |
videoUploadOnPasses | true | 是否啓用在用例運行通過後,上傳視頻至Dashboard,僅適用於錄製項目,如果關閉該功能,則僅上傳運行失敗的視頻 |
3.2.1.6 視圖
配置項 | 默認值 | 描述 |
---|---|---|
viewportHeight | 660 | 測試視圖下待測試應用程序的默認高度,單位爲pixels,可使用cy.viewport()命令覆蓋 |
viewportWidth | 1000 | 測試視圖下待測試應用程序的默認寬度,單位爲pixels,可使用cy.viewport()命令覆蓋 |
更多自定義選項,可查閱官方文檔,地址爲:https://docs.cypress.io/guides/references/configuration
3.2.1.7 命令行
除了使用配置文件進行配置以外,也可以使用命令行進行設置以下各個參數,如下所示:
cypress open --config pageLoadTimeout=30000,baseUrl=https://www.surpass.com
cypress run --config integrationFolder=tests,videoUploadOnPasses=false
3.2.1.8 Cypress.config()
除了直接在cypress.json文件中更改配置之外,也可以通過Cypress.config()去獲取或覆蓋某些配置項。其基本使用方法如下所示:
// 獲取所有config信息
Cypress.config()
// 獲取指定config信息
Cypress.config(name)
// 更改指定config信息
Cypress.config(name,value)
// 設置多個config項
Cypress.config(object)
示例代碼如下所示:
describe("測試Cypress.config",function(){
it("獲取defaultCommandTimeout",function(){
cy.log(`defaultCommandTimeout value is:${Cypress.config("defaultCommandTimeout")}`)
// 設置參數選項值
Cypress.config("defaultCommandTimeout",99999)
cy.log(`defaultCommandTimeout value is:${Cypress.config("defaultCommandTimeout")}`)
})
})
運行結果如下所示:
3.2.2 用例結構
Cypress是建立在Mocha和Chai之上,因此同時支持Chai的BDD和TDD兩種風格。如果你熟悉JavaScript風格的代碼,那麼在Cypress中寫測試用例是很容易上手的。
Mocha是一款適用於Node.js和瀏覽器的測試框架,可使用異步測試變得簡單靈活。
Cypress的測試風格繼承於Mocha,提供了describe()、context()、it()、specify()四個關鍵字,對於一條可執行的測試而言,必須包含以下兩個組成部分:
- describe()和context()等效,均表示一個測試套件或測試集
- it()和specify()等效,均表示一個測試用例
示例如下所示:
describe('我是一個測試集', () => {
it('測試用例-1', () => {
expect(1+2).to.eq(3)
});
it('測試用例-2', () => {
expect(3-2).to.eq(1)
});
it('測試用例-3', () => {
expect(3*2).to.eq(5)
});
});
最終的運行結果如下所示:
更多測試用例的組織和編寫會在後續詳細講解
3.2.3 重試機制
重試是Cypress一個非常重要的功能,在瞭解重試的概念後,有助於寫出更加健壯的測試。
3.2.3.1 命令和斷言
命令和斷言是兩種在Cypress中測試常用的兩種方法,示例如下所示:
/// <reference types="cypress" />
describe('', () => {
let baseUrl="https://example.cypress.io/todo"
it('測試用例-1', () => {
// 一個命令 visit
cy.visit(baseUrl);
// 一個命令 get,一個斷言 should
cy.get(".header input").should("have.class","new-todo");
// 三個命令 get 和 type
cy.get('.new-todo').type('todo A{enter}').type('todo B{enter}');
// 一個命令 get,一個斷言 should
cy.get('.todo-list li').should('have.length', 4);
});
});
最終的運行結果如下所示:
讓我們一起來看看最後一行的命令和斷言,如下所示:
cy.get('.todo-list li').should('have.length', 4);
以上命令和斷言,是通過cy.get()命令查找頁面的DOM,在找到與選擇器匹配的元素,然後進行斷言嘗試,而現在很多WEB應用幾乎都是異步的。以最後一行代碼爲例,Cypress不能在查詢DOM元素(todo-list)的同時又去檢查其元素個數是否爲4個。因此在出現以下情況,就會出現問題,如下所示:
- 1.當運行命令或斷言時,應用程序沒有更新DOM時,怎麼辦?
- 2.當運行命令或斷言時,應用程序正在等待後端返回響應,而頁面暫時沒有結果時,怎麼辦?
- 3.當運行命令或斷言時,應用程序正在進行密集計算,而導致頁面顯示未及時更新時,怎麼辦?
以上幾種情況,在測試過程中非常常見,一般處理辦法在斷言前,設置一個等待時間,但這個等待時間,在不同環境中還不能完全統一,還是會導致經常出錯。而Cypress處理這種問題,則非常智能,如下所示:
在實際運行時,如果cy.get()命令之後的斷言通過,則認爲該命令成功執行。如果失敗,則cy.get()命令將重新查詢應用程序的DOM,再進行斷言。如果失敗,則再次執行cy.get()命令查詢DOM,再進行斷言。依此類推,直至斷言成功或cy.get()命令超時爲止。
正是因爲Cypress的這種自動重試功能避免了在測試代碼中出現硬編碼的等待。使測試代碼更加健壯。
3.2.3.2 多重斷言
在日常測試中,有時候需要對一個數據進行多次斷言,Cypress提供一種方法叫多重斷言,其定義爲:單個命令後跟多個斷言。在斷言時,Cypress將按順序重試每個命令,即當第一個斷言通過後,在進行第二個斷言時仍會重試第一個斷言。當第一和第二個斷言都通過後,在進行第三個斷言,仍然會重試第一和第二個斷言,依此類推。來看看以下示例:
/// <reference types="cypress" />
describe('多重斷言示例', () => {
let baseUrl="https://example.cypress.io/todo";
it('演示用例-1', () => {
cy.visit(baseUrl);
cy.get('.new-todo').type('todo A{enter}').type('todo B{enter}');
cy.get('.todo-list li')
.should('have.length',4)
.and(($li) => {
expect($li.get(2).textContent,'first item').to.equal('todo A')
expect($li.get(3).textContent,'second item').to.equal('todo B')
});
});
});
.and()斷言是.should()的別名,它是.should()的自定義回調函數,包含兩個expect()斷言。
最終的運行結果如下所示:
上面代碼共有三個斷言,分別是should和兩個expect。在測試過程中,如果第二個斷言失敗了,則第三個斷言不會執行,如果第二個斷言執行通過,整個命令還未超時,在執行第三個斷言前,會再次重試第一個和第二個斷言。
修改代碼使得第二個斷言出現失敗,代碼如下所示:
/// <reference types="cypress" />
describe('多重斷言示例', () => {
let baseUrl="https://example.cypress.io/todo";
it('演示用例-1', () => {
cy.visit(baseUrl);
cy.get('.new-todo').type('todo A{enter}').type('todo B{enter}');
cy.get('.todo-list li')
.should('have.length',4)
.and(($li) => {
expect($li.get(2).textContent,'first item').to.equal('toda A')
expect($li.get(3).textContent,'second item').to.equal('todo B')
});
});
});
在第二個斷言運行失敗後,第三個斷言則不會被執行。在執行命令超時後,會在運行頁面顯示第一個斷言執行成功,第二個斷言執行失敗,如下圖所示:
3.2.3.3 重試條件
Cypress並不會重試所有命令。當命令可能改變待測應用程序的狀態時,則將不會進行重試操作(例如.click()命令)。Cypress僅會重試查詢DOM的命令,例如cy.get()、.find()、.contains()等等。
如果需要查詢更多重試的命令,可查閱API文檔中Assertions文檔https://docs.cypress.io/guides/references/assertions
重試的超時時間默認爲4s,也可通過defaultCommandTimeout進行設置。
3.2.3.3.1 增加超時時間
我們也可以通過修改所有命令的超時時間,例如,將全局的默認超時時間設置爲10s,如下所示:
cypress run --config defaultCommandTimeout=10000
以上這種方式可以修改全局的超時時間,但不推薦。相反,我們可以通過設置單個命令的超時時間{ timeout: ms },而更加靈活的控制各個命令的超時時間,示例如下所示:
/// <reference types="cypress" />
describe('多重斷言示例', () => {
let baseUrl="https://example.cypress.io/todo";
it('演示用例-1', () => {
cy.visit(baseUrl,{timeout:1000});
cy.get('.new-todo').type('todo A{enter}').type('todo B{enter}');
cy.get('.todo-list li')
.should('have.length',4)
.and(($li) => {
expect($li.get(2).textContent,'first item').to.equal('toda A')
expect($li.get(3).textContent,'second item').to.equal('todo B')
});
});
});
以上代碼,設置訪問網站的超時時間爲1s,運行結果如下所示:
3.2.3.3.2 禁用重試
如果將超時時間設置爲0,其本質上是禁用重試機制,示例如下所示:
cy.get('.new-todo',,{timeout:0}).type('todo A{enter}').type('todo B{enter}');
原文地址:https://www.jianshu.com/p/55819e173a5d
本文同步在微信訂閱號上發佈,如各位小夥伴們喜歡我的文章,也可以關注我的微信訂閱號:woaitest,或掃描下面的二維碼添加關注: