Angular8 中引入 Jest 单元测试
文章目录
Angular 项目默认的单元测试框架是 Karma + jasmine, 帅帅我的项目 AngBoot: https://github.com/DreamLi1314/angboot 部署到 CI 上之后发现跑 Karma 测试用例时需要启动浏览器, 虽然可以配置解决, 但是在自己部署到云服务上时
./gradlew clean build
每次都要在 angular 的 test 阶段失败(没有浏览器—虽然也可以跳过test), 因此感觉特别不爽, 于是乎, 就提了一个 Feature----Feature #15:https://github.com/DreamLi1314/angboot/issues/15, 也就有了这篇文章,
好了, 一起瞅瞅吧!
1. Jest 和 Karma 的区别
1.1 Karma 存在的问题
- Karma 需要先把 Angular 应用整体编译之后再在浏览器中跑测试,跑测试的时间比较长;
- Karma 测试结果不稳定(很可能是因为异步操作引起的),单个文件和整体测试时的测试结果不一致;
- 报错信息模糊不清,无法定位问题。特别是在有大量测试需要修复的情况下,难以定位问题的根本原因。
1.2 Jest 的优势
- 不需要整体编译,可以单文件测试
- 测试结果稳定
- 报错清楚,易于定位问题
- 开箱即用,基本算是全家桶,包含了测试需要的大部分工具:测试结构、断言、spies、mocks
- 直接提供了测试覆盖率报告
- 快照测试
- 非常强大的模块级 mock 功能
- watch 模式仅仅测试和被修改文件相关的测试,速度非常快
所以还等什么, 赶快跟着帅帅一起迁移到 Jest 吧…
2. 迁移到 Jest
2.1 安装 Jest
npm install --save-dev jest jest-canvas-mock jest-junit @types/jest @angular-builders/jest
npm install jest-codemods
jest
---- Jest 测试框架jest-junit
---- jest junit 测试jest-canvas-mock
---- 配置好的 mock 数据@types/jest
---- Jest 的 typings@angular-builders/jest
— jest 构建器jest-codemods
---- 代码插件
2.2 配置 Jest
- a. angular.json 中 修改
test
构建器:
"test": {
"builder": "@angular-builders/jest:run",
"options": {
"reporters": [
"default",
"jest-junit"
]
}
},
同时移除
e2e
模块(不移除的话由于 e2eprotractor
还要使用 jasmine 所以需要去解决冲突, 帅帅我不需要这玩意就直接删除了, 保持环境干净, 并且公司产品也是好几个版本都没写 e2e 因此帅帅我果断移除掉, 需要的朋友自行百度解决jest
和jasmine
的引用冲突即可.)
- b. 在项目根路径下添加
jest.config.js
配置文件:
module.exports = {
globals: {
'ts-jest': {
tsConfigFile: './tsconfig.spec.json',
},
},
setupFiles: ["jest-canvas-mock", "<rootDir>/src/setupJest.ts"]
};
- c. 创建自己的 setup 文件以及全局的 mock 文件:
// setupJest.ts
import "./jestGlobalMocks.ts"; // jest 全局的 mock
// jestGlobalMocks.ts
const mock = () => {
let storage = {};
return {
getItem: key => key in storage ? storage[key] : null,
setItem: (key, value) => storage[key] = value || "",
removeItem: key => delete storage[key],
clear: () => storage = {},
};
};
Object.defineProperty(window, "localStorage", {value: mock()});
Object.defineProperty(window, "sessionStorage", {value: mock()});
Object.defineProperty(window, "getComputedStyle", {
value: () => ["-webkit-appearance"]
});
jsdom 并没有实现所有的 window 上的对象和方法,所以有时我们需要自己给 window 打个补丁。
在这里 mock localStorage 是可选的,如果我们在代码中并没有使用。但是 mock getComputedStyle 是必须的,因为 Angular 会检查它在哪个浏览器中执行。如果没有 mock getComputedStyle,我们的测试代码将无法执行。
- c. 修改
tsconfig.spec.json
的compilerOptions/types
: 将jasmine
替换为jest
- d. 在 package.json 中添加执行 test 的script
"test": "JEST_JUNIT_OUTPUT=./build/test-results/junit.xml npm run ng -- test angboot-web --ci --runInBand --reporters=default --reporters=jest-junit",
"test:watch": "JEST_JUNIT_OUTPUT=./build/test-results/junit.xml npm run ng -- test angboot-web --ci --runInBand --reporters=default --reporters=jest-junit --watch"
-
- angboot-web 是项目名, 参看
angular.json/projects/*
- angboot-web 是项目名, 参看
-
--ci --runInBand
CI服务器通常在单核上运行您的代码,因此并行化可能会降低测试速度。如果遇到这种情况,请使用--runInBand
标志明确告诉Jest您要一对一地运行测试(就像Karma或Mocha一样)
3. 移除 Karma
3.1 移除 Karma 的依赖包
npm uninstall karma karma-chrome-launcher karma-coverage-istanbul-reporter karma-jasmine karma-jasmine-html-reporter @types/jasmine @types/jasminewd2 jasmine-core jasmine-spec-reporter
简单点就删掉
package.json
总带有karma
和jasmine
的依赖
3.2 移除 e2e 和 protractor
- protractor.conf.js
- app.e2e.spec.ts
- tsconfig.e2e.json
- …
4. 运行测试
npm run test
此时,在命令行中运行测试命令,就应该能够顺利把测试跑起来并通过了。如果没有通过,可能是因为我们在 src/tsconfig.spec.json 中的 file 配置中有 test.js 的配置,这是 Karma 的 setup 文件,删掉这行配置并删除对应的文件,(src/tsconfig.app.json 中出现的 test.js 也可一并删除),重新跑一遍测试命令.