上一篇文章我們介紹了測試金字塔。今天我們就從金字塔的最下面開始,來分享如何在Angular專案中,導入Jest這個單元測試框架。
Jest 是一個流行的行為驅動開發(BDD) JavaScript 測試框架,最初由 Facebook 開發。廣泛應用於 JavaScript 和 TypeScript 開發的應用。
Jest的特點在於,他提供了開箱即用的體驗,通常不需要繁瑣的配置。並且Jest 可以同時執行多個測試,這有助於加快測試速度,特別是在大型應用中。最後快照測試,模擬函式和模組,覆蓋率報告,等測試常用的功能也都有提供。
Jest的語法也非常簡單。
test('adds 1 + 2 to equal 3', () => {
expect(1 + 2).toBe(3);
});
test
代表一個獨立的測試案例,expect(1 + 2).toBe(3)
代表預期 1+2 的結果應該要是 3。
那為什麼要用Jest呢? Angular本身沒有搭配的測試框架嗎?
其實Angular針對測試本身提供了 Angular Testing Utilities 搭配 Jasmine 和 Karma 作為測試的解決方案和環境。
Angular Testing Utilities,提供了一些內建的測試工具和服務,支援Angular應用與測試框架的交互,以便於撰寫和執行測試。
Jasmine 是一個行為驅動開發(BDD)的測試框架,而Karma則是一個測式執行器,能夠在瀏覽器中運行測試。
那麼為什麼不用原本提供的測試環境,而是要導入Jest呢?
首先,從Angular 16 開始,Karma 已經走入deprecated 並且 Jest 已經被加入Angular的實驗模式。所以可以理解成,Angular團隊正逐漸向Jest靠攏。除了這個原因外,實務層面包含幾個面向:
1. 簡化的配置和使用
- 零配置:Jest 提供了一個開箱即用的體驗,通常不需要繁瑣的配置,而 Karma + Jasmine 通常需要更多的配置和設置工作。
- 簡單的語法:Jest 的測試語法更加直觀,開發者可以更輕鬆地編寫測試用例。
2. 速度與性能
- 並行測試:Jest 能夠並行運行測試,這樣可以顯著提高測試速度。Karma 每次都會啟動一個瀏覽器實例,這在大型應用中會導致測試變得緩慢。
- 監聽文件變更:Jest 自帶的監聽功能可以在文件變更時自動運行相關測試,這使得開發過程更加高效,而 Karma 的監聽功能可能不如 Jest 方便。
3. 強大的模擬功能
- 內建模擬:Jest 內建了模擬功能,使得開發者能夠輕鬆地模擬函式和模組,這對於測試依賴於外部資源的代碼非常方便。Karma 和 Jasmine 雖然也有模擬功能,但通常需要額外的配置和庫支持。
4. 快照測試
- 快照測試:Jest 提供的快照測試功能可以輕鬆檢查 UI 元件的輸出,這對於測試應用的視覺一致性非常有用。Karma 和 Jasmine 雖然可以實現類似的功能,但需要更多的設置。
5. 代碼覆蓋率報告
- 自動生成報告:Jest 能夠自動生成代碼覆蓋率報告,這使得開發者可以輕鬆了解測試的全面性。雖然 Karma 也可以生成覆蓋率報告,但設置和配置上通常更為複雜。
6. 社區支持和生態系統
- 活躍的生態系統:Jest 擁有一個活躍的開發者社區,並且與其他現代工具(如 React、Vue)有著良好的整合,這使得使用 Jest 的開發者能夠受益於豐富的資源和支持。
7. 現代開發流程的適應性
- 適合現代工具鏈:Jest 在許多現代 JavaScript 生態系統中被廣泛使用,與 Webpack、Babel 等工具的整合相對簡單,更適合現代前端開發的需求。
準備好專案後第一步要做的就是移除Jasmine和Karma
1. 移除Jasmine和Karma
npm uninstall karma karma-chrome-launcher karma-coverage karma-jasmine karma-jasmine-html-reporter @types/jasmine jasmine-core
2. 移除angular.json中的測試
"test": { "builder": "@angular-devkit/build-angular:karma", "options": { "polyfills": [ "zone.js", "zone.js/testing" ], "tsConfig": "tsconfig.spec.json", "inlineStyleLanguage": "scss", "assets": [ { "glob": "**/*", "input": "public" } ], "styles": [ "src/styles.scss" ], "scripts": [] } }
3. 安裝 jest
npm i --save-dev jest @types/jest jest-preset-angular
jest
測試框架。@types/jest
是一個 TypeScript 的型別定義檔案包,提供了 Jest 框架的 TypeScript 支援。jest-preset-angular
是一個專為 Angular 應用設計的 Jest 預設配置套件,提供了一些預設設置和工具,以便於在 Angular 環境中使用 Jest。4. 在資料夾中建立 setup-jest.ts 檔案
加入檔案後,於其中import jest-preset-angular
import 'jest-preset-angular/setup-jest';
5. 使用 jest cli 指令建立 jest.config 檔案
npx jest — init
執行完後會新增一個 jest.config.js 或 .ts的設定檔。
將設定檔中的setupFilesAfterEnv
調整為setupFilesAfterEnv: ['<rootDir>/setup-jest.ts'],
假設我們使用的是 jest.config.ts 就需要安裝 ts-node。
ts-node
是一個 TypeScript 執行環境,允許我們直接運行 TypeScript 文件,而無需手動將它們編譯為 JavaScript。這樣,開發者可以更方便地測試和執行 TypeScript 代碼。npm install ts-node --save-dev
6. 更新 tsconfig.spec.json 檔案
{ "extends": "./tsconfig.json", "compilerOptions": { "outDir": "./out-tsc/spec", "types": [ "jest" // 1 ], "esModuleInterop": true, // 2 "emitDecoratorMetadata": true // 3 }, "include": [ "src/**/*.spec.ts", "src/**/*.d.ts" ] }
extends
:這個屬性表示當前配置文件繼承自其他配置文件(此例中是./tsconfig.json
)。這意味著當前的配置會基於父配置進行擴展,並添加或覆蓋一些特定的選項。outDir
:
- 設定編譯輸出的目錄,此例中指定為
./out-tsc/spec
。這意味著編譯後的 TypeScript 文件將被輸出到這個目錄中。types
:
- 這個屬性告訴 TypeScript 編譯器要加載哪些型別定義。此例中,
"jest"
表示要加載 Jest 的型別定義,以便在編寫測試時可以使用 Jest 提供的函式和匹配器,並獲得相應的型別檢查和自動補全支持。esModuleInterop
:
- 這個選項允許在 TypeScript 中使用 ES 模組語法導入 CommonJS 模組。設置為
true
時,可以使用import
語法導入 CommonJS 模組,這有助於提高與其他模組系統的兼容性。emitDecoratorMetadata
:
- 這個選項啟用裝飾器元數據的生成。在使用 Angular 或類似框架時,這通常是必需的,因為許多框架依賴於裝飾器(例如,用於依賴注入)。設置為
true
會在編譯時生成額外的元數據,幫助這些框架正確運行。include
:
- 這個屬性告訴 TypeScript 編譯器要包含哪些文件。在這個例子中,編譯器會包括所有在
src
目錄下,擁有.spec.ts
和.d.ts
擴展名的文件。.spec.ts
文件通常是測試文件,而.d.ts
文件是型別定義文件。7. 最後在 package.json 中加入執行 Jest測試的指令
"test-jest": "jest --verbose", "test-jest:coverage": "jest --coverage", "test-jest:watch": "jest --watch"
到這裡我們就成功在將Jasimine和Karma替換成Jest了! 下一篇文章我們會討論如何撰寫單元測試和測試切割的力度。
參考文獻:
Angular unit testing with Jest 2023 - by Megha D Parmar
Moving Angular CLI to Jest and Web Test Runner - by Doug Parker