前端自动化测试
(内容有的来自其他帖子,自己做了整合)
一个需要多人合作、开发周期长的大规模前端项目 会出现
代码风格各不相同 、代码过度耦合 、组件职责不够单一 、新同学上手慢,因为项目大、杂、乱,
我们是否能够保证项目的稳定?如果在后续的维护中,一不小心影响到了之前的功能怎么办?类似这种通用库,发布一个有严重 Bug 的版本,可能就会造成成百上千的项目一起崩溃
我们需要自动化测试。
对核心组件覆盖自动化测试,可以有效地保证组件功能的单一,起到警醒工程师的作用,而不至于让不同的业务代码相互耦合;新同学可以通过单测快速 get 到这个组件打算做什么、有什么能力,不论是后续的维护还是重构都会更有底气
技术选型上使用 Jest + React Testing Library + Cypress + Storybook。
vue项目推荐用vitest
单元测试 or 端对端测试
单元测试是更细粒度的、从代码组件层次进行的功能测试
端对端测试是从用户视角,从项目整体展开的测试
仅通过 Jest , 没办法完成前端的所有单元测试,因为与常规的接口逻辑测试不同,前端的单元测试涉及到 Dom 和事件的模拟,我们还需要选用一个辅助库来协助我们模拟相关的场景。
Jest 是基础的测试库,是安装 Enzyme 和 React Testing Library 的前置条件
安装jest
ts 版本
npm install --save-dev jest @types/jest @jest/types
初始化配置
npx jest --init
- 前两个配置选项是字面意思,不赘述了。
- 单测环境(jsdom):因为我们会涉及到 dom 的单测,不仅仅是纯逻辑,如果是纯逻辑的选 node。
- 是否需要覆盖率报告(no):暂时用不上,后面覆盖率章节会着重介绍。
- 编译代码(babel): 可以转 ES5,避免一些兼容性问题。
- 每次测试完是否清理 mock、实例等结果(yes): 每次测试完成后会清理 mock 等上次测试的结果,可以避免用例之间的互相影响
运行
yarn jest
匹配器
Jest使用“匹配器”的机制让你可以使用各种方法进行测试
精确匹配
// 我希望执行这个函数》 传入的值 ,tobe 期望得到的值
test("adds 1 + 2 to equal 3" //name
, () => {
expect(add(1, 2)).toBe(3);
});
比如
test('获取最大值',()=>{
expect(FindMax([1,3,46,7])).toBe(46); //期望得到46
})
toEqual
递归检查对象或数组的每个字段
test("对象赋值", () => {
const data = { one: 1, two: 51 };
expect(data).toEqual({ one: 1, two: 2 });
});
//会标注期望的值的地方哪里有问题
使用 toStrictEqual 优于使用 toEqual。 toEqual 只是简单地忽略 undefined 值,而 toStrictEqual 则考虑它们。
匹配相反的 not
真值
toBeNull只匹配nulltoBeUndefined只匹配undefinedtoBeDefined与toBeUndefined相反toBeTruthy匹配任何if语句为真toBeFalsy匹配任何if语句为假
test("真值", () => {
const n = null;
expect(n).toBeNull(); //为空通过
expect(n).toBeDefined(); //undifend 取反
expect(n).not.toBeUndefined();///undifend 取反
expect(n).not.toBeTruthy(); //为假 加了 not
expect(n).toBeFalsy(); //取的假
});
数字
大多数的比较数字有等价的匹配器。
对于比较浮点数相等,使用 toBeCloseTo 而不是 toEqual,因为你不希望测试取决于一个小小的舍入误差。 精度问题
字符串
您可以检查对具有 toMatch 正则表达式的字符串︰
test('there is no I in team', () => {
expect('team').not.toMatch(/I/);
});
数组和可迭代对象
数组foreach的迭代寻找
你可以通过 toContain来检查一个数组或可迭代对象是否包含某个特定项:
const shoppingList = [ 'diapers', 'kleenex', 'trash bags', 'paper towels', 'milk',];
test('shoppingList数组中包含milk', () => {
expect(shoppingList).toContain('milk');
expect(new Set(shoppingList)).toContain('milk');
});
例外
若你想测试某函数在调用时是否抛出了错误,你需要使用 toThrow。
测试异步代码
异步请求的代码测试
Promise
test('the data is peanut butter', () => {
return fetchData().then(data => {
//期望的data 匹配器‘peanut butter’返回
expect(data).toBe('peanut butter');
});
});
哪里需要匹配在哪里添加
Async/Await
test('the data is peanut butter', async () => {
const data = await fetchData();
expect(data).toBe('peanut butter');
});
test('the fetch fails with an error', async () => {
expect.assertions(1);
try {
await fetchData();
} catch (e) {
expect(e).toMatch('error');
}
});
使用单个参数调用 done Jest会等done回调函数被调用执行结束后,再结束测试。
test('the data is peanut butter', done => {
function callback(error, data) {
if (error) {
done(error); //最后执行
return;
}
try {
expect(data).toBe('peanut butter');
done();
} catch (error) {
done(error);
}
}
fetchData(callback);
});
分组测试
t给了我们更优雅的写法---分组,我们使用describe函数分组,如下
describe('分别测试Count的4个方法', () => {
test('测试increase', () => {
//1
})
test('测试decrease', () => {
//2
})
test('测试double', () => {
//3
})
test('测试half', () => {
//4
})
})
作者:catboy
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
beforeEach是在每一个test函数执行之前,会被调用;afterEach则是在每一个test函数执行之后调用;beforeAll是在所有test函数执行之前调用;afterAll则是在所有test函数执行之后调用。
可以自定义这4个周期的函数执行路径
describe("分别测试Count的4个方法", () => {
//所有
beforeAll(() => {
console.log("before all tests!");
});
// 之前
beforeEach(() => {
console.log("before each test!");
// count = new Count()
});
// 后面说有
afterAll(() => {
console.log("after all tests!");
});
//每一个函数后面
afterEach(() => {
console.log("after each test!");
});
test("测试increase", () => {
// count.increase()
console.log(1);
});
test("测试decrease", () => {
// count.decrease()
console.log(2);
});
test("测试double", () => {
console.log(3);
});
test("测试half", () => {
// count.half()
console.log(4);
});
});
让jest监听文件变化
"scripts": {
"test": "jest",
"test-watch": "jest --watch"
},
改变文件
会出现
- 按
a键运行所有测试代码 - 按
f键只运行所有失败的测试代码 - 按
p键按照文件名筛选测试代码(支持正则) - 按
t键按照测试名筛选测试代码(支持正则) - 按
q键盘推出watch模式 - 按
enter键触发一次测试运行
生成测试覆盖率文件
"scripts": {
"test": "jest",
"test-watch": "jest --watch",
"coverage": "jest --coverage"
},
检查我们测试代码占用整个项目的覆盖率是多少