# 自動化測試簡介及導入 - [常見自動測試介紹](#常見自動測試介紹) - [E2E testing(Cypress)導入](#E2E-testing-\(Cypress\)導入) - [參考資料](#參考資料) ## 常見自動測試介紹 ### 單元測試 (Unit testing) > 以「測試引擎」及「斷言庫」所組成的測試類型。以程式碼的最小單位 (function) 進行測試,保護程式邏輯不會在 ***系統維護、重構*** 的過程中遭到破壞,並確保程式碼品質 **Pros** 1. 測試以 function 為主,因此可以得到較高的撰寫效益,是最容易撰寫的測試類型。 2. 測試即文件,若有豐富的測例,可減少閱讀或重構程式碼時茫然的機會 **Cons** Time is money,初學時會花較多時間,導致放棄撰寫單元測試。 #### 常見工具 | 類型 | 名稱 | | -------- | -------- | | 測試引擎 | Mocha, Jest | | 斷言庫 | chai, power-assert | **Tips** 可以在 Vscode 裝 Jest 的擴充功能,可以直接在 editor 看測試結果 ![](https://i.imgur.com/YLoiaFD.png) ------------- ### 端對端測試 (End-to-end testing) > Aka E2E tesing,直接以完整 UI、實際系統進行測試,開啟瀏覽器並模擬使用者的真實操作,然後診斷其結果是否符合預期。很可惜的是,大部分的端對端測試都是人工進行的 **Pros** 人非聖賢、孰能無過,人工測試總有疏漏之處,既便有完整的測試案例與腳本,測試人員或是自己也不見得會每次照著 SOP 進行操作 **Cons** 若以真實後端打 API,可能有非預期的錯誤(childrens, foots, totalSize 為 0 ...等等),故可能需多維護一個純 mock 版的測試(直接寫死 response),只測前端功能(用以甩鍋) ### 常見工具 *I don't know which is the best; however, we are all the best* | 名稱 | 學習成本 | 速度 | 瀏覽器支援度 | 優點 | 雷點 | | -------- | -------- | -------- | -------- | -------- | -------- | | Cypress | 低 | 快 | Chrome 友善 | 好寫好用 | 不支援 ES7, Native Browser Events | Testcafe | 中 | 快 | 貌似皆可 | 還沒用過 | 寫法較特殊 | | Puppeteer | 高 | 快 | Chrome only | 還可以用來爬蟲 | ? | | Selenium Webdriver | 高 | 跟 IE 一樣 | 高 | 老牌,執行後可以去泡咖啡 | ? | ---- ## E2E testing(Cypress)導入 ### 1. 安裝 * vue-cli 建專案時就選他 * npm install cypress -D 沒裝過的話會幫自動產出相關 json config, example files ``` ./ │ cypress │ │ │ └───fixtures(放 data, user 之類的 json) │ │ │ ... │ │ │ └───integration(測試文件區) │ │ │ │ │ └───examples │ │ │ │ example1.spec.js │ │ │ │ example2.spec.js │ │ │ │ ... │ │ │ │ │ └───tests │ │ │ login.spec.js │ │ │ ... │ │ │ │ └─--plugins │ │ │ ... │ │ │ └─--support(自訂指令) │ │ ... │ └───src │ │ App.vue │ │ ... │ │ cypress.json └───package.json ``` ### 2. 調整 eslint (若無 eslint 可忽略) > 在 env 區塊中加入 cypress,讓 cypress 的 keywords 不會被當成未宣告變數 ```javascript= // .eslintrc.js env: { ... 'cypress/globals': true, }, ``` ### 3. 新增測例 > 以 describe 包裝測試類型,it 區隔測例 ```javascript= // cypress/integration/tests/login.spec.js describe('登入畫面', () => { it('Login button exists (登入 button 存在)', () => { cy.visit('/') cy.contains('button', '登入') }) }) ``` ### 4. 在 html 元素中加入 cypress 專用識別屬性 data-cy 就只是個一般的屬性而已,用來作為 selector ![](https://i.imgur.com/YRv2hc8.png) 但這樣對 element-ui 的 組件會無效,所以需自訂 directive ```javascript= import util from '@js/util' const addCy = { bind: async (el, bindings) => { await util.delay(0) const { arg, modifiers, expression } = bindings const [label, relation, selector] = [arg, modifiers, expression] if (selector && relation.parent) { const selectEl = el.closest(selector.substring(1, selector.length - 1)) selectEl.setAttribute('data-cy', label) } else if (selector && relation.child) { const selectEl = el.querySelector(selector.substring(1, selector.length - 1)) selectEl.setAttribute('data-cy', label) } else { el.setAttribute('data-cy', label) } }, } export default addCy ``` ![](https://i.imgur.com/FtGdNqX.png) ## 參考資料 - [保哥 - 一次搞懂單元測試、整合測試、端對端測試之間的差異](https://blog.miniasp.com/post/2019/02/18/Unit-testing-Integration-testing-e2e-testing) - [Why Cypress? - Cypress Official Document](https://docs.cypress.io/guides/overview/why-cypress.html#In-a-nutshell)