公司的项目已经由javascript全面转为TypeScript,这并不代表TypeScript比JavaScript更优秀。而是随着项目规模和参与开发的团队规模的扩大,类型约束对项目的质量有非常明显的帮助。测试对于提升软件质量的帮助是被公认的,它能排除某些程序逻辑问题还是次要的,更重要的是测试还能帮助程序员理解业务乃至业务的边界。测试代码还能一定程度替代文本注释,帮助人们理解代码的意图。
开始
项目初始化,对于TS的项目,Jest支持两种方案:babel
或ts-jest
,这里选择ts-jest
。安装jest
以及依赖:
mkdir your-project
npm init -y
tsc init
pnpm add --save-dev jest ts-jest @types/node @types/jest ts-node
配置
Jest
npx ts-jest config:init
初始化配置文件,也可以运行
npx jest --init
❯ npx jest --init
The following questions will help Jest to create a suitable configuration for your project
✔ Would you like to use Typescript for the configuration file? … yes
✔ Choose the test environment that will be used for testing › node
✔ Do you want Jest to add coverage reports? … yes
✔ Which provider should be used to instrument code for coverage? › v8
✔ Automatically clear mock calls, instances, contexts and results before every test? … no
建议采用后者,因为后者创建的配置文件中包含全部的配置以及解释,不用到的配置也被注释掉,方便调整。
再打开配置文件,调整常见开发环境下的测试特性:
- 忽略测试目录:因为用TS,有些项目会先构建dist目录,然后运行,所以需要把dist目录忽略掉。
testPathIgnorePatterns:["/node_modules/","/dist"]
- 设置转义,ts扩展名的文件,用
ts-jest
处理。transform:{"^.+\.(t|j)s$": "ts-jest"}
Package.json
修改tsconfig.json
:输出目录outDir
设置为./dist
,(如有)设置.gitignore
的忽略目录
实践
在src目录中创建文件foo.class.ts
和 foo.class.spec.ts
// foo.class.ts
export class Foo {
constructor(private _name: string) {}
get name(): string {
return this._name;
}
set name(value: string) {
this._name = value;
}
}
// foo.class.spec.ts
import { Foo } from "./foo.class";
describe("Foo测试", () => {
it("初始化", () => {
const foo = new Foo("foo");
expect(foo).toBeInstanceOf(Foo);
});
it("name属性", () => {
const foo = new Foo("foo");
expect(foo.name).toBe("foo");
});
it("设置name属性", () => {
const foo = new Foo("foo");
expect(() => (foo.name = "bar")).not.toThrow();
expect(foo.name).toBe("bar");
});
});
运行jest
,应该得到如下结果:
❯ jest
PASS src/foo.class.spec.ts
Foo测试
✓ 初始化 (3 ms)
✓ name属性 (1 ms)
✓ 设置name属性 (1 ms)
--------------|---------|----------|---------|---------|-------------------
File | % Stmts | % Branch | % Funcs | % Lines | Uncovered Line #s
--------------|---------|----------|---------|---------|-------------------
All files | 100 | 100 | 100 | 100 |
foo.class.ts | 100 | 100 | 100 | 100 |
--------------|---------|----------|---------|---------|-------------------
Test Suites: 1 passed, 1 total
Tests: 3 passed, 3 total
Snapshots: 0 total
Time: 3.337 s, estimated 4 s
Ran all test suites.
说明项目最基本的环境已经配置成功。
丝滑设置
以上的项目仅能保证在初始化时可以用,而实际的项目很少有如此简单的。比如说项目中会用到很多本地类库,由于路径复杂,往往会设置别名(Alias),此时必须同步tsconfig和jest.config两者的配置。例如tsconfig.json有:
"baseUrl": "./" ,
"paths": {
"src/*": ["./src/*"],
"common": ["./src/common"]
}
在src/common/index.ts
创建简单的内容
export const DEFAULT_NAME="Tester"
修改src/foo.class.ts
import { DEFAULT_NAME } from "common";
export class Foo {
constructor(private _name: string = DEFAULT_NAME) {}
get name(): string {
return this._name;
}
set name(value: string) {
this._name = value;
}
}
此时,如果不做任何操作,程序可以被正确构建,但是无法通过jest,因为此时的jest,还无法正确识别common
。所以需要在jest.config.ts
中加入:
// …… 其他内容
moduleNameMapper: {
"^common$": "<rootDir>/src/common",
},
// ……其他内容
效率
(如果电脑的性能还OK)实时监控程序改变(保存),触发重新运行测试代码。
jest --watchAll
vscode
vscode的插件,打开的项目中如果有jest的配置,会自动执行测试脚本。
ext install Orta.vscode-jest