资讯 / 全部资讯 / 正文

企鹅极客丨产品高质量交付利器之前端自动化测试(上)

前言

对客户交付高质量的产品是企业的核心目标之一,而单元测试是实现这一目标的重要手段之一。通过单元测试,可以确保产品的每个部分都经过了严格的测试,降低产品出现缺陷的概率,提高产品的可靠性和稳定性。同时,单元测试的结果可以为客户提供更加准确的产品质量报告,帮助客户更好地了解产品的优点和缺陷。此外,单元测试还可以提高开发人员的信心和积极性,促进团队的合作和创新,为客户提供更加优质的产品和服务。

然而作为一个前端开发者来说,我们所承担的不单单只是保证开发任务的完成,在交付所完成的项目之前更要保证的是质量问题,如何保证交付的质量是一个很值得探讨的问题,大多数开发者在开发过程中会针对当前所开发的内容进行自测,但是避免不了会有一些疏漏或者测试不到位的地方,导致一些很常见的bug的出现。也可能对于一个方法或者组件的调整导致引用其方法或组件的其他组件受到影响而没有进行测试导致交付的bug

所以单元测试还是非常有必要的,但是更多的时候却忽略了单元测试的重要性,一个完整的项目单元测试的存在还是非常重要的,这篇博客将会带你重新认识单元测试,另一方面将教会你从零开始搭建环境和如何使用单元测试。

为什么要写单元测试

  1. 必要性:JavaScript缺少类型检查,编译期间无法定位到错误,单元测试可以帮助你测试多种异常情况。

  2. 正确性:测试可以验证代码的正确性,在上线前做到心里有底。

  3. 自动化:通过console虽然可以打印出内部信息,但是这是一次性的事情,下次测试还需要从头来过,效率不能得到保证。通过编写测试用例,可以做到一次编写,多次运行。

  4. 保证重构:互联网行业产品迭代速度很快,迭代后必然存在代码重构的过程,那怎么才能保证重构后代码的质量呢?有测试用例做后盾,就可以大胆的进行重构。

单元测试和端对端测试

对于大多数开发者来说对于Unit(俗称:单元测试)可能听说的比较多,对于E2E(端到端测试)不是那么特别的了解。那么两者之间有什么区别呢?

单元测试

单元测试(Unit)是站在程序员的角度测试,unit测试是把代码看成一个一个的组件,从而实现每一个组件的单独测试,测试内容主要是组件内的每一个函数的执行结果或返回值是否和测试中断言的结果一致。

端对端测试

端对端测试(E2E)是把我们的程序堪称是一个黑盒子,我不懂你内部是怎么实现的,我只负责打开浏览器,把测试内容在页面上输入一遍,看是不是我想要得到的结果。

unit测试是程序员写好自己的逻辑后可以很容易的测试自己的逻辑返回的是不是都正确。e2e代码是测试所有的需求是不是都可以正确的完成,而且最终要的是在代码重构,js改动很多之后,需要对需求进行测试的时候测试代码是不需要改变的,你也不用担心在重构后不能达到客户的需求。

单元测试原则

在编写单元测试时,我们需要mock掉那些依赖于外部系统或库的组件,例如数据库、网络请求等。这样可以确保测试单元独立于外部环境和其他单元的状态,只测试当前单元的功能。而对于那些依赖于内部方法或类的组件,则可以直接进行测试,因为它们是当前单元的一部分。

对于ComposeApi模块,我们应该为其编写独立的单元测试,并使用真实的实现进行测试,因为它是被其他使用者所调用的。这样可以确保ComposeApi模块的代码质量和可维护性,并且在使用ComposeApi模块时,可以保证其功能正常。而对于使用ComposeApi模块的其他模块,在编写单元测试时,应该将其依赖Mock掉,以确保测试只关注当前模块的逻辑,不受其他依赖的影响。这样可以确保测试单元独立于外部环境和其他单元的状态,只测试当前模块的功能。

准备工作

在进行单元测试之前,需要选择适合自己的测试工具。本文采用Jest作为测试工具,因为Jest支持断言和覆盖率测试,具有写法简单、功能强大等优点。使用Jest可以帮助我们更好地进行单元测试,提高代码质量和可靠性。

开始搭建环境我们应该先对以下知识点有所了解:

  1. vite

  2. typescript

  3. vue3

搭建单元测试环境

这里默认你已经有了一个可以添加测试环境的项目(如果没有请自行创建)。

首先安装对应的依赖:

yarn add jest --dev                  
yarn add @types/jest --dev
yarn add babel-jest --dev
yarn add @babel/preset-env --dev
yarn add @vue/vue3-jest --dev
yarn add ts-jest --dev
yarn add @vue/cli-plugin-unit-jest --dev
yarn add @vue/test-utils@next --dev
yarn add @babel/preset-typescript --dev
yarn add babel-plugin-transform-vite-meta-env --dev
yarn add jest-environment-jsdom --dev
yarn add babel-plugin-transform-import-meta --dev

注:这里使用的是yarn安装的依赖,不要过于纠结包管理工具,根据自己的喜好自行选择即可。

依赖安装完成之后,在src目录下创建tests文件夹,这个文件夹用来存放关于测试相关的文件。

在根目录创建jest.config.js对Jest进行初始化的基本配置:

module.exports = {
cache: false,
collectCoverage: true,
// babel预设
transform: {
"^.+\\.vue$": "@vue/vue3-jest", // 支持导入Vue文件
"^.+\\.jsx?$": "babel-jest", // 支持import语法
'^.+\\.tsx?$': 'ts-jest', // 支持ts
'.+\\.(css|styl|less|sass|scss|png|jpg|ttf|woff|woff2)$': 'jest-transform-stub' // 支持导入css文件
},
moduleFileExtensions: ['js', 'json', 'jsx', 'ts', 'tsx', 'vue'],
// 路径别名
moduleNameMapper: {
'^@/(.*)$': '<rootDir>/src/$1',
},
testEnvironment: 'jsdom',
testEnvironmentOptions: {
customExportConditions: ['node', 'node-addons'],
},
testMatch: [
'**/tests/**/*.test.[jt]s?(x)',
],
preset: '@vue/cli-plugin-unit-jest/presets/typescript-and-babel'
};

由于这里使用的是TypeScript也需要对tsconfig.json进行调整,让测试文件也可以支持TypeScript:

//  省略了其他配置项,其他配置根据项目要求自行配置即可
{
"compilerOptions": {
// ...
"types": ["vite/client", "jest"] // 指定类型为jest
},
"include": [
// ...
"tests/**/*.ts" // 指定单元测试路径
]
}

因为Node无法运行TypeScript这里需要使用babelTypeScript进行编译,要配置babel的相关配置,在根目录创建babel.config.js

module.exports = {
presets: [
[
"@babel/preset-env",
{
targets: {
node: "current"
}
}
]
],
plugins: [
'@babel/plugin-transform-arrow-functions',
'babel-plugin-transform-vite-meta-env',
['babel-plugin-transform-import-meta', { module: 'ES6' }]
],
};

对环境配置完成之后为了方便调用测试命令,可以在package.jsonscripts添加快捷指令:

{
"scripts": {
// ...
"test": "jest"
},
}

常用断言

  1. toBe(): 测试具体的值

  2. toEqual(): 测试对象类型的值

  3. toBeCalled(): 测试函数被调用

  4. toHaveBeenCalledTimes(): 测试函数被调用的次数

  5. toHaveBeenCalledWith(): 测试函数被调用时的参数

  6. toBeNull(): 结果是null

  7. toBeUndefined(): 结果是undefined

  8. toBeDefined(): 结果是defined

  9. toBeTruthy(): 结果是true

  10. toBeFalsy(): 结果是false

  11. toContain(): 数组匹配,检查是否包含

  12. toMatch(): 匹配字符型规则,支持正则

  13. toBeCloseTo(): 浮点数

  14. toThrow(): 支持字符串,浮点数,变量

  15. toMatchSnapshot(): jest特有的快照测试

  16. not.toBe(): 前面加上.not就是否定形式

创建第一个单元测试

对单元测试环境配置完成之后,接下来可以添加测试文件了:

// test/index.test.ts

test("1+1=2", () => {
expect(1+1).toBe(2);
});

添加完成之后执行命令:

yarn test

看到控制台输出:

 PASS  tests/index.test.ts

----------|---------|----------|---------|---------|-------------------
File | % Stmts | % Branch | % Funcs | % Lines | Uncovered Line #s
----------|---------|----------|---------|---------|-------------------
All files | 0 | 0 | 0 | 0 |
----------|---------|----------|---------|---------|-------------------

Test Suites: 1 passed, 1 total
Tests: 1 passed, 1 total
Snapshots: 0 total
Time: 1.798 s
Ran all test suites.
✨ Done in 5.32s.


前端自动化测试在产品高质量交付中扮演着至关重要的角色。通过单元测试和端对端测试的结合,我们可以更全面地检测出前端代码中的问题,并及时修复,从而保证产品的稳定性和可靠性。同时,基础环境的搭建也是非常关键的一步,只有在稳定的环境下才能进行高效的测试工作。


通过本文对单元测试已经有了深刻的认识,以及如何写一个简单的单元测试,后续会推出针对Vue进行单元测试,敬请期待《企鹅极客丨产品高质量交付利器之前端自动化测试(下)》



关于未名企鹅
     
未名企鹅以“连接健康”为使命,致力于提供生命健康领域的大数据产品和解决方案,帮助客户实现数据驱动的业务增长。

未名企鹅中的“未名”代表北大,寓意人文精神,生命健康领域正是体现人文关怀的产业;“企鹅”象征科技,未名企鹅的创始团队毕业于北大,技术力量来自腾讯,公司以未名企鹅命名是希望以人文情怀加上科技力量来推动生命科学行业数字化发展。
医药健康产业大数据技术和解决方案专家