E2E 測試之 Cypress

背景

寫測試好像一直是橫亘在開發眼前的一個問題,在業務開發時間比較緊急的時候,測試可能是第一個被拋棄的(境界不夠。

在實際業務開發中有幾次修改代碼後因為測試不充分,發布後原功能受影響。所以我們當前的首要需求是快速回歸產品功能,盡量保證原有業務不能受到影響同時可以節省測試資源,在選擇測試方式的時候就偏向於 E2E 測試。

現在有一些測試框架可供選擇,CasperJS、Nightwatch 等等。CasperJS 只能是無界面瀏覽器測試,不列入考慮。在 TestCafe 和 Cypress 中猶豫過,TestCafe 支持常見瀏覽器,支持 ES6/ES7 和 TS,安裝也方便。

最終選擇了 Cypress,主要是覺得開箱即用,文檔比較清晰美觀,語法用起來比較舒服,最重要的一點是測試跑在 Chrome 的標籤頁里,和平時開發沒什麼區別。這種情況下其實很適合開發時模擬各種場景,比如新增一個介面,約定好了介面定義但是介面還沒好,就可以利用 Cypress 來模擬請求開發了。一定程度上也可以實現 mock 的功能。同樣,測試 fail 了也可以直接調試。

安裝

下載速度比較慢,耐心等待一下。安裝完之後根目錄下會出現 cypress 文件夾,文件夾目錄結構如下:

|-- fixtures|-- integration| `-- example_spec.js|-- plugins| `-- index.js`-- support |-- commands.js `-- index.js

fixtures 文件夾存放自定義 json 文件,integration 文件夾編寫測試,plugins 和 support 是非必須使用的文件夾,需要自定義指令的時候會用到。

編寫一個最基礎的測試

以一個包含 E2E 測試常用操作的測試用例來介紹 Cypress 的基本使用。結合官方文檔給的案例一起看風味更佳。

  1. 打開、跳轉網頁:打開 eleme h5 訂餐首頁
  2. 滾動首頁餐廳列表,是否正確滾動載入
  3. 填寫搜索詞,提交搜索,正確跳轉頁面
  4. 點擊搜索第一項,頁面正確展示

添加測試文件

在 cypress/integration 文件夾下新建測試文件。如 example.spec.js

根據喜好選擇某種風格編寫測試

Cypress 對 chai、Expect.js 風格的都支持,還拓展了一些斷言,

頁面的展示離不開介面的返回結果。根據測試用例模擬不同的介面返回。不建議使用真實請求測試,完全可以自己設計介面返回進行測試。

第一步開啟請求攔截:

Start a cy.server()

第二步設置目標請求的相關內容。cy.route() 指定的請求會被攔截下來,可以根據需求修改 response、status 等等:

Provide a cy.route()

另外,設置請求時可以使用 cy.fixture(),通過這個 command 可以指定請求 response 從特定文件讀取。

例如:

cy.fixture(list.json).as(listInfo)cy.route(list, @listInfo).as(getList)

就是攔截 /list 請求,將返回替換成 cypress/fixtures/list.json 文件的內容。

回到本例,我們首先需要用 cy.visit() 跳轉到需要測試的頁面。

關於滾動 Cypress 提供了介面 cy.scrollto(),獲取 DOM 元素用 cy.get()。用法類似平時使用的 querySeclector。

it(列表滾動載入, () => { cy.visit(https://h5.ele.me/) // 滾動載入 cy.scrollTo(0, 600) cy.get(.shoplist > section).should(have.length, 10)})

接下來獲取輸入框並輸入搜多次,輸入可以使用 cy.type()

it(輸入搜索詞,結果正確展示, () => { cy.visit(https://h5.ele.me/) // 點擊跳轉搜索頁面 cy.get(.search).click() cy.wait(200) cy.get(input).type(麻辣燙) cy.get(button).click() // 目標頁面地址包含 search 點擊列表第一項 cy.wait(500) cy.url().should(include, search) cy.get(.shop).first().click() // 跳轉至商家詳情頁,找到購物車元素 cy.wait(500) cy.get(.cartview)})

這裡面使用的 cy.wait() 意思是等待多少毫秒,因為介面是真實數據,事實上真實測試的時候使用我們攔截過的請求,一般不需要使用等待某個時間。

一個修改請求的例子

比如我們想模擬 5xx 這種異常返回,當然可以使用 charles 來攔截請求修改狀態。但是使用 Cypress 的話,編寫測試用例的同時就可以在瀏覽器模擬場景,檢測是否符合預期結果。

cy.route({ url: /xxxx, response: , status: 500})

測試結果分析

可視化測試結果如下圖:

每一個 case 運行的過程和結果會顯示在面板上,運行出錯不會妨礙其他 case,對於檢查結果還是比較清晰明了的。對於運行失敗的 case,可以像平時開發一樣用 Chrome Devtools 檢查 dom 或網路請求。

常用 api

除了上文介紹到的一些介面,還有一些比較常用的api:

Hooks

describe(Hooks, function() { before(function() { // runs once before all tests in the block }) after(function() { // runs once after all tests in the block }) beforeEach(function() { // runs before each test in the block }) afterEach(function() { // runs after each test in the block })})

cy.viewport()

可以方便的修改視窗,就像使用 Chrome 模擬不同設備窗口一樣。比如設置了 cy.viewport(iphone-6) 就會以 iphone6 的大小跑測試。

Environment Variables

類似於全局變數,在根目錄下的 cypress.json 中

{ "env": { "foo": "bar", "some": "value" }}

便可以在測試文件中通過 Cypress.env(foo) 來訪問。

注意:

  • 後端修改介面時,可能需要修改測試中的介面返回,否則可能會不匹配實際情況。
  • Cypress 對多瀏覽器測試支持並不友好,不能做到像 browserstack 那樣測試各個瀏覽器兼容性。這方面可以看一下 這篇文章。接下來我們也可能使用阿里雲移動測試來測試兼容性。
  • Cypress 對 fetch 的兼容不好,處理方法詳見 issue95。

總結一下使用 Cypress 寫測試的基本思路

  • 確定是否需要攔截請求,用 cy.route 修改請求,按照設計好的測試用例設定 response。
  • 用 cy.visit 訪問需要測試的頁面。
  • 根據實際情況,一般校驗元素可見性、是否是禁用狀態、數量、文案是否正確等等。
  • 運行測試,在控制面板查看測試結果。

其實上手很快,關鍵是要了解業務流程,合理劃分功能點寫測試用例。

關於 Cypress

介紹了基本的使用方法,接下來稍微探究一下這個 Cypress 測試工具。

Cypress 可以概括為是許多測試框架的集合,可以使用 Mocha、Karma、Capybara 等等。用官方的說法是 Cypress 基本上可以取代 Karma 了??。

Cypress esentially replaces Karma because it does all of this already and much more.

Karma 其實是一個 runner,分 client 和 sever。Cyrpess 和 Karma 相似:監聽文件,server 與 client 進行通訊,向開發者輸出測試結果。

Cypress 並沒有使用 Selenium / Webdriver。Cypress 運行在瀏覽器上下文中,幾乎不與外界產生真實交流。當然也提供一些介面比如 cy.request() 可以去真實請求介面。

不過 Cypress 實際上更像是一個程序、一個開發工具,可以測試任何在瀏覽器里運行的程序,和你所使用的框架是什麼沒關係。換句話說,可以邊測試邊開發。

支持的功能和一些關鍵的特性在 官網 有明確的說明。

一時的使用並不意味著上了終身保險,能滿足你的需求才是最重要的。介紹 Cypress 是提供一種比較有意思的測試方式,實際上寫的測試效果如何還是取決於你的代碼。


推薦閱讀:

作為一個互聯網公司,測試團隊是否有存在的必要?
開講啦!一鍵GET失效分析實戰技能(視頻乾貨)
微博上流傳了一個回答問題測試偶像的網站,很多很多人證實了其真的很準確,請問這是怎麼做到的?
斯坦福—比奈IQ測試有參考價值嗎?
Jmeter壓測實例分享——新手兒也能一學就會!

TAG:测试 | 前端开发 |