什麼是 JavaScript 自動化測試?
JavaScript 自動化測試 是一套透過程式碼驗證軟體功能是否符合預期的技術體系,旨在確保系統具備「一致性」與「可靠性」。其核心原則包含 3A 原則 (Arrange, Act, Assert):分別代表準備測試情境、執行操作行為與驗證結果。測試體系通常分為針對最小程式碼單元的 單元測試 (Unit Testing)(如使用 Jest 測試函式邏輯)以及模擬真實使用者路徑的 端對端測試 (E2E Testing)(如使用 Cypress 跑完購物流程)。高品質的測試不僅能攔截潛在 Bug,更能作為活的文件(Living Documentation),讓開發團隊在頻繁更動程式碼時仍能維持高品質的穩定輸出,是專業軟體開發中不可或缺的安全網。
測試 這件事情是為了一致性,為了不讓伴侶不信任,在男女之間交往一致性也是很重要的一環。這份 JavaScript 測試 全攻略將帶您掌握提升軟體品質的關鍵。
john rempel 等人提出信任包含可預測、可依賴和信念三個要素:
- 可預測: 判斷依據就是過去伴侶行為的一致性。
- 可依賴: 代表相信且願意依賴伴侶協助解決問題。
以程式測試來說,每次測試會期待能得到相同結果,並且認為能夠依賴系統解決問題。
JavaScript 測試核心原則:3A 與黑箱測試
寫測試前要問三個問題:
- 在什麼情境?
- 要測試什麼?
- 預期的結果?
測試的步驟上大致會遵守 3A 原則:
- Arrange:準備物件、建立物件、物件設定 (fixture) -> 情境。
- Act:操作物件 -> 測試內容。
- Assert:驗證結果符合預期 -> 預期結果。
好的單元測試
- 執行夠快
- 會得到相同結果
- 跟其他測試完全獨立
- 理論上不需要 DB、網路,用 Mock Server 或是 Mock Object 模擬外部傳回資料
測試是為了開發速度和產品品質,不要因為著急而跳過測試,沒有測試的話會花更多時間在上線前的來回,可能有些問題還沒修好就上線,引發更多新問題,但什麼都要測試嗎?
- 追求 “測到關鍵邏輯”,關鍵的測試有測到更重要
- 測試是為了速度與品質
- 不好的 “快” 不是 “真的快”
- 寫測試的時候應避免重複寫原來的程式邏輯
建議做黑箱測試也就是測試流程與結果即可,在測試公開的介面或元件的過程中其實也會順便測試到內部邏輯,當撰寫 E2E 測試的時候也有單元測試覆蓋的概念,雖然 E2E 的運行成本較高,但針對可能會頻繁更改的內部實作做單元測試也有點浪費時間。
另外 E2E 測試也可以當作一個文件,可以告訴不熟系統的人關鍵操作流程以及定義什麼是正常的操作,按照使用者故事跑過網站的關鍵流程,並且交由助理工程師來協助驗收。
推薦工具:
- BDD (行為驅動測試) 框架是 Cucumber 可以參考看看
- StoryBook 提供一個元件操作介面來做元件測試
Comparing JavaScript Testing Frameworks
單元測試 (Unit Testing):Jest 與 Enzyme 的應用
當前端開發元件化以後,最基本的就是針對元件做 單元測試。第一次寫測試的話可以先問自己幾個問題:
- 單元測試 該怎麼撰寫?
- 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 測試 (End-to-End):Cypress 實戰演練
Cypress 提供針對測試的配置、撰寫、執行、除錯完整的 end-to-end test (E2E 測試) 的解決方案。比較特別的是 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
FAQ:JavaScript 測試常見問題
Q1:我該如何決定測試覆蓋率 (Code Coverage) 應該達到多少?
A:並非越高越好。 追求 100% 的覆蓋率往往會導致開發者為了湊數字而寫出無意義的測試。對於核心業務邏輯(如支付計算、權限判斷),應要求 90% 以上的高覆蓋率;對於純樣式或不常變動的 UI 元件,維持 50%-60% 即可。重點在於「關鍵路徑」必須被保護。
Q2:什麼是 TDD (測試驅動開發)?它真的能提升效率嗎?
A:TDD (Test-Driven Development) 是指「先寫測試,再寫功能」的模式。短期內,撰寫測試會佔用 20%-30% 的開發時間;但長期來看,它能大幅減少 Debug 的時間與後期回歸測試的成本。更重要的是,TDD 能強迫您在寫 Code 之前先釐清需求規格,產出更乾淨的介面設計。
Q3:Cypress 與 Selenium 有什麼不同?
A:Selenium 是透過外部驅動器 (Web Driver) 操控瀏覽器,速度較慢且配置複雜;而 Cypress 是直接執行在瀏覽器內部的腳本,具備極高的執行速度、自動等待機制與強大的除錯介面(時空旅行)。對於現代 JavaScript 應用,Cypress 是更友善且高效的選擇。
喜歡這篇文章,請幫忙拍拍手喔 🤣


