快速入门
环境检测
D:\Vue-Automated-Testing>node -v
v12.13.0
D:\Vue-Automated-Testing>npm -v
6.12.0
初始化项目, 生成 package.json 文件, 可以一路回车
npm init
安装 jest 使用 yarn 或使用 npm 安装
yarn add --dev jest
npm install --save-dev jest
Jest的文档统一使用
yarn指令, 但是用npm同样可行, 可以通过 yarn官方文档 进行yarn和 npm 对比
为了便于文件管理, 创建三个文件夹
├─server (服务器代码)
├─src (逻辑代码)
├─test (测试代码)
package.json (包管理器)
Hello world!
在 src 文件夹下创建 index.js 文件
export function test() {
return 'Hello World!'
}
然后在 test 文件夹下创建 index.test.js 测试文件
import { hello } from '../src/index'
test('Hello World!', () => {
escape(hello()).toBe('Hello World!')
})
由于使用了 import ES6 的语法, 故而要使用 Babel
通过 npm 安装依赖
npm install @babel/core@7.4.5 @babel/preset-env@7.4.5 -D
在项目的根目录下创建 babel.config.js ,通过配置 Babel 使其能够兼容当前的 Node 版本。
module.exports = {
presets: [
[
'@babel/preset-env',
{
targets: {
node: 'current',
},
},
],
],
};
然后配置脚本命令, 将如下代码添加到 package.json 中:
{
"scripts": {
"test": "jest"
}
}
最后,运行 yarn test 或者 npm run test,Jest 将输出如下信息:
PASS test/index.test.js
√ Hello World! (1 ms)
喜大普奔, 我们已经成功写好了第一个测试用例了
然后我们看下测试到底干了什么
每个 test 方法都是一个小模块, 它接受两个参数, 第一个参数是该模块的测试描述, 第二个参数是一个函数, 是你所需要的执行的测试用例
这个测试用例很简单, 每次要测试一个值时都会使用 expect 函数。它接收一个值, expect 函数后往往会跟一个"匹配器", 已验证 expect 函数里面的值, 这里使用的是 toBe 匹配器, 意思是 匹配器内的值与 expect 函数里的值严格等于
匹配器
常用匹配器
jest 为我们提供一些常用的匹配器
| 匹配器 | 说明 |
|---|---|
toBe | 严格等于 |
toEqual | 匹配值 |
toBeNull | 匹配 Null |
toBeUndefined | 匹配 undefined |
toBeDefined | 匹配定义 |
toBeTruthy | 匹配真值 |
toBeFalsy | 匹配假值 |
toBeGreaterThan | 大于 |
toBeGreaterThanOrEqual | 大于等于 |
toBeLessThan | 小于 |
toBeLessThanOrEqual | 小于等于 |
toBeCloseTo | 浮点问题 |
toMatch | 用来判断一个字符串是否包含一个指定的值 |
toContain | 用来判断一个数组(Set 对象)是否包含一个指定的值 |
not | 取反 |
toThrow | 匹配异常 |
更多匹配器
要获得匹配器的完整列表,请查看 参考文档。
测试方法
下面我们开始为一个函数写测试,这个函数的功能是解析时间对象为字符串。首先创建 utils.js 文件:
/**
* Parse the time to string
* @param {(Object|string|number)} time
* @param {string} cFormat
* @returns {string}
*/
export function parseTime(time, cFormat) {
if (arguments.length === 0) {
return null
}
const format = cFormat || '{y}-{m}-{d} {h}:{i}:{s}'
let date
if (typeof time === 'object') {
date = time
} else {
if ((typeof time === 'string') && (/^[0-9]+$/.test(time))) {
time = parseInt(time)
}
if ((typeof time === 'number') && (time.toString().length === 10)) {
time = time * 1000
}
date = new Date(time)
}
const formatObj = {
y: date.getFullYear(),
m: date.getMonth() + 1,
d: date.getDate(),
h: date.getHours(),
i: date.getMinutes(),
s: date.getSeconds(),
a: date.getDay()
}
const time_str = format.replace(/{(y|m|d|h|i|s|a)+}/g, (result, key) => {
let value = formatObj[key]
// Note: getDay() returns 0 on Sunday
if (key === 'a') { return ['日', '一', '二', '三', '四', '五', '六'][value ] }
if (result.length > 0 && value < 10) {
value = '0' + value
}
return value || 0
})
return time_str
}
接下来, 创建名为 utils.test.js 的文件。这个文件包含了实际的测试内容:
const utils = require('../src/utils')
const { parseTime } = utils
test('测试方法: parseTime', () => {
const d = new Date('2020-10-19 11:45:01') // 2020-10-19 11:45:01
expect(parseTime(d)).toBe('2020-10-19 11:45:01')
expect(parseTime(d, '{y}-{m}-{d} {h}:{i}')).toBe('2020-10-19 11:45')
expect(parseTime(d, '{y}年{m}月{d}日')).toBe('2020年10月19日')
expect(parseTime(d, '{a}')).toBe('一')
})
最后,运行 yarn test 或者 npm run test,Jest 将输出如下信息:
PASS test/utils.test.js
✓ Utils:parseTime (4ms)
测试通过了, 但却不是一个合格的测试用例, 要想写一个合格的测试用例, 我们必须要了解什么是测试覆盖率, 再了解这个之前我们先来一些基础配置
基础配置
执行命令初始化文件 jest.config.js
npx jest --init
目前我们只需了解一个配置(生成覆盖率文件)
module.exports = {
// The directory where Jest should output its coverage files
coverageDirectory: "coverage"
}
然后我们在 package.json 文件中继续添加一行
{
"script": {
"coverage": "npx jest --coverage"
}
}
然后运行
npm run coverage
测试覆盖率
----------|---------|----------|---------|---------|-------------------
File | % Stmts | % Branch | % Funcs | % Lines | Uncovered Line #s
----------|---------|----------|---------|---------|-------------------
All files | 70 | 50 | 100 | 68.42 |
index.js | 100 | 100 | 100 | 100 |
utils.js | 68.42 | 50 | 100 | 66.67 | 9,16-22
----------|---------|----------|---------|---------|-------------------
参数表说明:
- Stmts 语句覆盖率 每个语句是否都执行了
- Branch 分支覆盖率 条件语句是否都执行了
- Funcs 函数覆盖率 函数是否全部调用了
- Lines 行覆盖率 未执行的行数
说明还是有些地方并未测试到
修改代码
describe('测试方法:parseTime', () => {
const d = new Date('2018-07-13 17:54:01') // "2018-07-13 17:54:01"
it('timestamp', () => {
expect(parseTime(d)).toBe('2018-07-13 17:54:01')
})
it('ten digits timestamp', () => {
expect(parseTime((d / 1000).toFixed(0))).toBe('2018-07-13 17:54:01')
})
it('new Date', () => {
expect(parseTime(new Date(d))).toBe('2018-07-13 17:54:01')
})
it('format', () => {
expect(parseTime(d, '{y}-{m}-{d} {h}:{i}')).toBe('2018-07-13 17:54')
expect(parseTime(d, '{y}-{m}-{d}')).toBe('2018-07-13')
expect(parseTime(d, '{y}/{m}/{d} {h}-{i}')).toBe('2018/07/13 17-54')
})
it('get the day of the week', () => {
expect(parseTime(d, '{a}')).toBe('五') // 星期五
})
it('get the day of the week', () => {
expect(parseTime(+d + 1000 * 60 * 60 * 24 * 2, '{a}')).toBe('日') // 星期日
})
it('empty argument', () => {
expect(parseTime()).toBeNull()
})
})
测试结果
----------|---------|----------|---------|---------|-------------------
File | % Stmts | % Branch | % Funcs | % Lines | Uncovered Line #s
----------|---------|----------|---------|---------|-------------------
All files | 100 | 95.45 | 100 | 100 |
index.js | 100 | 100 | 100 | 100 |
utils.js | 100 | 95.45 | 100 | 100 | 40
----------|---------|----------|---------|---------|-------------------
语句覆盖率和行覆盖率都打到 100%, 说明测试是合格的