測試這件事情是為了一致性,為了不讓伴侶不信任,在男女之間交往一致性也是很重要的一環。
在日常的對話和相處過程中,彼此都會透過些方法來確認, John Rempel 等人提出信任包含可預測、可依賴和信念三個要素。
- 可預測判斷的依據就是過去伴侶行為的一致性
- 可依賴代表相信且願意依賴伴侶協助解決問題
以程式測試來說,每次的測試會期待能得到相同結果,並且認為能夠依賴系統解決問題。
舉個例子來說小編前公司是做看盤軟體,為了確保 Production 環境穩定,每天會在開盤前執行 E2E 測試確保網站運作正常,即便當錯誤發生也能即時寄信通知相關人員。
JavaScript 測試
寫測試前要問三個問題
- 在什麼情境?
- 要測試什麼?
- 預期的結果?
測試的步驟上大致會遵守 3A 原則
- Arrange: 準備物件、建立物件、物件設定 (fixture) -> 情境
- Act: 操作物件 -> 測試內容
- Assert: 驗證結果符合預期 -> 預期結果
好的單元測試
- 執行夠快
- 會得到相同結果
- 跟其他測試完全獨立
- 理論上不需要 DB、網路,用 Mock Server 或是 Mock Object 模擬外部傳回資料
測試是為了開發速度和產品品質,不要因為著急而跳過測試,沒有測試的話會花更多時間在上線前的來回,可能有些問題還沒修好就上線,引發更多新問題,但什麼都要測試嗎?
- 追求 “測到關鍵邏輯”,關鍵的測試有測到更重要
- 測試是為了速度與品質
- 不好的 “快” 不是 “真的快”
- 寫測試的時候應避免重複寫原來的程式邏輯
建議做黑箱測試也就是測試流程與結果即可,在測試公開的介面或元件的過程中其實也會順便測試到內部邏輯,當撰寫 E2E 測試的時候也有單元測試覆蓋的概念,雖然 E2E 的運行成本較高,但針對可能會頻繁更改的內部實作做單元測試也有點浪費時間。
另外 E2E 測試也可以當作一個文件,可以告訴不熟系統的人關鍵操作流程以及定義什麼是正常的操作,按照使用者故事跑過網站的關鍵流程,並且交由助理工程師來協助驗收。
推薦工具:
- BDD (行為驅動測試) 框架是 Cucumber 可以參考看看
- StoryBook 提供一個元件操作介面來做元件測試
Comparing JavaScript Testing Frameworks
單元測試
當前端開發元件化以後,最基本的就是針對元件做單元測試,第一次寫測試的話可以先問自己幾個問題:
- 單元測試該怎麼撰寫?
- Jest 的腳色是什麼?
- 什麼是 enzyme?
- 什麼是 shallow & mount ?
單元測試通常是一個自動化的測試,確保某一段程式碼 (單元) 有被正式執行,在測試時大多使用單元測試框架測試。
- 會呼叫被測試單元的入口點
- 檢查其中一個出口點,所以唯一出口較好測試
單元測試在測什麼
- 元件測試,import 後用 mount 然後 props 用假資料進行測試,模擬點擊
jest.fn()
- function 測試,import 後用假資料測試
- 非同步:
jest.fn()
- test fixture: 測試的時候特意準備的東西,讓測試可以順利跑完所需要,有些人會叫做 test context
- 包含測試
- 出口測試
- CUT: Code under test
- SUT: system under test
依照使用的框架或函式庫不同會有不同的測試工具,像 react 的話 facebook 官方就有 Jest。
Jest 對於單元測試來說非常方便而且也包含了覆蓋率的計算,最後會直接出一個報表給你,文章中也有推薦 enzyme,是 airbnb 開發的工具,據 react 官方說法是讓測試更簡單。
enzyme 只是讓我們更方便測試 react 用的外掛,主要是因為 react 有用到 virtual dom ,那測試又會需要去 render,所以 enzyme 就封裝了 react 原生的測試讓寫法更直覺。
- shallow: 只 render 第一層
- mount: full render,包含元件週期
- render
- simulate: 模擬 event
- setProps: 設定 props
- setState: 設定 state
- prop(key): retrieves prop value corresponding to the provided key
- state(key): retrieves state corresponding to the provided key
單元測試該怎麼撰寫
寫法上會用到以下三個基本關鍵字 describe , it , expect,這是撰寫單元測試的語法架構,寫完這三項就是基本的測試了。
- describe: 主要是拿來整理 it 用(在這邊又可以用 test 代替),相關的 it 就可以包在 describe 裡面作更進一步的分類整理。
- it: 是最小的測試單位,所以每一項測試都要寫在某個 it function 裡。it 第一個參數是測試名稱,其實就是給你註解到底這個測試要幹嘛,然後搭配 before、beforeEach、after、afterEach 做進階操作
- expect: 按照名字來看就是你預期他到底怎樣,搭配 it 這個測試項目,看跑出來的結果是不是跟 expect 中的一樣,這就是基本的測試了
1 | import React from "react"; |
E2E 測試
Cypress 提供針對測試的配置、撰寫、執行、除錯完整的 end-to-end test 的解決方案,比較特別的是 Cypress 也像 Redux 的專案一樣提供了時空旅行的功能,並且提供了方便的介面讓我們更容易去針對測試進行除錯。
這次就用貓貓點擊大賽參戰的範例來帶大家超快速入門,來看看怎麼讓機器來取代 Popcat 的人工點擊!!!
原始碼: https://github.dev/LinYenCheng/popcat-cypress
Cypress 在使用上其實也很簡單,只要透過簡單的安裝設定就能夠直接執行並撰寫測試了,不一定要測試自己開發的網站,針對網路上的任何站台都能夠執行測試腳本。
Cypress 安裝設定
如果是 npm 的專案
npm install cypress --save-dev
首先要設定 npm script
1 | { |
安裝完完並設定之後,雖然專案資料夾都是全空的,但其實就可以執行了,這時候 Cypress 會偵測到我們是第一次執行,會自動將相關配置及範例加入。
第一次執行
cypress open
>
接著 Cypress 會自動加入相關預設的資料夾配置如下
- fixtures: 存放假資料或是常數值
- integration: 測試撰寫的地方
- plugins: 沒有想要修改預設功能一般不會用到
- support
- commands: 擴充共用的函式可以統一放在這邊
第一次啟動後的畫面
此外其實若想修改預設配置,也可以透過設定 cypress.json
來達到相關效果,底下是基本的範例可以看出我們能多設定像是重試次數、影片錄製等等參數,設定檔相關說明可以參考設定檔的參考文件。
1 | { |
Cypress 測試撰寫
Popcat 貓貓點擊大賽參戰確認!!! 一個最簡單的測試腳本如下:
1 | context("popcat.spec", () => { |
- Cypress visit():
cy.visit()
模擬瀏覽器開啟網站 - Cypress wait():
cy.wait()
模擬等待 - Cypress get():
cy.get()
類似 jQuery 的選擇器,可以協助我們找出網頁元素
學前端這麼多年,第一次覺得派上用場 😅 在台灣,每秒鐘都有上萬隻貓正在張開嘴巴。
- 分析 DOM
這個部分其實就會使用到 Chrome 的開發者元件,透過檢視,我們可以發現主要的網站很單純沒有太多設計,我們就只要針對 .cat-img
這個 class 進行模擬點擊就可以了,甚至是沒有針對直接對整個網頁觸發鍵盤事件也會有效果。
- 觸發事件
參戰最簡單的方法其實就是透過 console 來執行,不過這次是想透過測試工具 XD 至於如何使用 Chrome 開發者工具歡迎參考之前寫過的文章,相信可以快速入門的。
1 | var event = new KeyboardEvent("keydown", { |
- 觀察 API
可以發現是 API 主要步驟有兩個
- 透過 reload 來換 token
- 累積次數一陣子後透過 POP 這個 API 集中將累積次數 (pop_count) 送到後端
相關 API
如果短時間打太頻繁其實也是會被阻擋:
提醒大家運動家精神 XD
重複的執行也是會得到 403 的錯誤,這時候需要把整個測試關掉重開。
Cypress in Linux with Xvfb
CI/CD 在 Linux 環境上執行 Cypress 時會需要先安裝 Xvfb 但在執行上有時候會遇到問題,可以透過以下指令排解。
- ps -ef | grep Xvfb
- ps -ef | grep Xvfb | grep -v grep | awk ‘{print $2}’ | xargs kill -9
喜歡這篇文章,請幫忙拍拍手喔 🤣