手机网站建站步骤论文,浙江温州最新消息,校园时空网站建设分析,昆明做网站建设的公司哪家好由于格式和图片解析问题#xff0c;可前往 阅读原文 前端自动化测试在提高代码质量、减少错误、提高团队协作和加速交付流程方面发挥着重要作用。它是现代软件开发中不可或缺的一部分#xff0c;可以帮助开发团队构建可靠、高质量的应用程序
单元测试#xff08;Unit Testi… 由于格式和图片解析问题可前往 阅读原文 前端自动化测试在提高代码质量、减少错误、提高团队协作和加速交付流程方面发挥着重要作用。它是现代软件开发中不可或缺的一部分可以帮助开发团队构建可靠、高质量的应用程序
单元测试Unit Testing和端到端测试End-to-End Testing是两种常见的测试方法它们在测试的范围、目的和执行方式上有所不同。单元测试和端到端测试不是相互排斥的而是互补的。它们在不同的层面和阶段提供了不同的价值共同构成了一个全面的测试策略
单测和端测区别
单元测试(Unit)
单元测试关注于最小的可测试单元如函数、方法或模块目的是验证代码中的每个独立单元如函数是否按照预期工作通常是自动化的、快速执行的且不依赖于外部资源或其他模块验证单个代码单元的行为提供快速反馈并帮助捕获和修复问题
端到端测试(End-to-End)
从用户角度出发测试整个应用程序的功能和流程模拟真实的用户交互和场景从应用程序的外部进行测试。跨多个模块、组件和服务进行以确保整个应用程序的各个部分正常协同工作涉及用户界面UI交互、网络请求、数据库操作等以验证整个应用程序的功能和可用性
总之单元测试主要关注代码内部的正确性而端到端测试关注整体功能和用户体验。结合使用这两种测试方法可以提高软件的质量和可靠性。在项目中尤其是公共依赖如组件库至少都需要单测端测相对来说比较繁琐点但是也是程序稳定的重要验证渠道
单元测试 - Jest
这里使用Jest作为单元测试工具Jest 是一个用于 JavaScript 应用程序的开源测试框架。它是由 Facebook 开发和维护的通常用于单元测试。Jest 具有简单易用的 API、丰富的功能和强大的断言库广泛应用于前端开发和 Node.js 环境中
安装
➜ npm install jest -D初始化
使用npx进行交互式生成默认的配置文件它会提示你每步的选择
➜ npx jest --init
The following questions will help Jest to create a suitable configuration for your project✔ Would you like to use Jest when running test script in package.json? … yes
✔ Would you like to use Typescript for the configuration file? … no
✔ Choose the test environment that will be used for testing › jsdom (browser-like)
✔ 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? … yes✏️ Modified test/package.json Configuration file created at test/jest.config.js默认配置文件大概是下面的内容配置中有很多注释提供我们参考对于默认的配置就不用删除多语的注释了方便参考。通常都是对需要的配置项做修改即可
const config {// All imported modules in your tests should be mocked automatically// automock: false,// Automatically clear mock calls, instances, contexts and results before every testclearMocks: true,// Indicates whether the coverage information should be collected while executing the testcollectCoverage: true,// An array of glob patterns indicating a set of files for which coverage information should be collected// collectCoverageFrom: undefined,// The directory where Jest should output its coverage filescoverageDirectory: coverage,// An array of regexp pattern strings used to skip coverage collection// coveragePathIgnorePatterns: [// /node_modules/// ],// Indicates which provider should be used to instrument code for coveragecoverageProvider: v8,// Make calling deprecated APIs throw helpful error messages// errorOnDeprecated: false,// A list of paths to directories that Jest should use to search for files in// roots: [// rootDir// ],// The test environment that will be used for testingtestEnvironment: jsdom,// 省略其他...
};module.exports config;常用的配置 collectCoverageboolean值用来生成覆盖率报告通常也可以使用命令行--coverage参数生成 moduleFileExtensions对于引入文件可以省去文件后缀jest会根据规则一一匹配 moduleNameMapper模块匹配规则告诉jest改模块的匹配路径 {moduleNameMapper: {// 当匹配到 .css 等结尾的文件时对应 /__mocks__/style-mock.ts 文件\\.(css|less|scss|sass)$: rootDir/__mocks__/style-mock.ts,// 当匹配 ui 开头的的对应到 src 文件夹ui/(.*): rootDir/src/$1,},
}setupFiles在测试环境准备后和安装jest框架前做一些配置常用来添加一些全局环境模拟数据 setupFilesAfterEnv在安装jest框架后对jest做一些扩展相比setupFiles更加通用 testEnvironmentjest模拟的环境可以选择node、jsdom来模拟node和浏览器环境 testMatch指定要测试哪些文件 transform使用一些插件对代码进行转义以便jest可以理解如设置tsx转义
以上是最基本的配置jest的配置还是很多的还要官方有列举了一个表可以随时翻阅不用死记
转译器
Jest中有转义器的概念来帮助它理解编写的代码可以比做babel对代码做一些转换来兼容浏览器差不多一样的道理 模块引用转换 在单个测试文件中都会引入我们编写的代码然后对此代码的功能进行测试而前端通常都是以esmodule的形式进行函数的导出jest默认使用的是commonjs对于module语法jest不认识就会报错 import { sum } from ../core; // 报错describe(第一个测试, () {// ...
})那么可以对jest添加转义器将esmodule模块的代码转换成commonjs就可以了。打开配置文件 // jest.config.js
{transform: {^.\\.(ts|tsx|js|jsx)$: [babel-jest,{presets: [[babel/preset-env, { targets: { node: current } }]]},],},
}上面使用了 babel-jest和 babel/preset-env的依赖包需要安装下 ➜ npm i babel-jest babel/preset-env -D这样就可以解决esmodule语法不识别的问题 转换typescript目前项目中的文件都是以ts编写的而默认情况下jest只识别js文件的那么就需要对ts进行转译让jest识别 // jest.config.js
{transform: {^.\\.(ts|tsx|js|jsx)$: [babel-jest,{presets: [/* 其它... */[babel/preset-typescript]]},],},
}需要安装对应的babel/preset-typescript除了使用ts转义器也可以使用ts-jest直接运行ts代码 得益于ts的转译插件可以让jest的测试文件或配置文件都写成ts类型的而在ts文件中对于不识别的jest工具会报错或者没有提示安装jest的类型文件包types/jest来告诉ts对应的jest类型然后进行配置 // tsconfig.json
{types: [jest]
}转换jsx假如项目中使用了jsx那么也要对jsx进行转义这里以vue jsx为例 // jest.config.ts
{transform: {^.\\.(ts|tsx|js|jsx)$: [babel-jest,{// 省略其他plugins: [vue/babel-plugin-jsx],},],},
}基本断言
基本环境配置好后就到了测试的时间了我们先来最简单的配置用起
// __tests__/demo.spec.ts
import { sum } from src/utils;describe(第一个测试, () {it(分组1, () {expect(sum(1, 2)).toBe(3);});
});// 或者不用分组
test(第一个测试, () {expect(sum(1, 2)).toBe(3);
});
这里介绍下几个关键字基本概念
describe用来描述当前测试的整体内容it用来分组测试test用来描述当前测试无分组expect判断参数的值其的返回值有多个断言方法上面使用了toBe也就是等于的意思。除了次此断言有很多断言的条件你可以点击这里阅读官方文档
执行测试
# 现在package中配置 jest 脚本然后执行测试
➜ npm run test # npx jestPASS __tests__/demo.spec.ts第一个测试✓ 分组1 (2 ms)----------|---------|----------|---------|---------|-------------------
File | % Stmts | % Branch | % Funcs | % Lines | Uncovered Line #s
----------|---------|----------|---------|---------|-------------------
All files | 100 | 100 | 100 | 100 | utils.ts | 100 | 100 | 100 | 100 |
----------|---------|----------|---------|---------|-------------------
Test Suites: 1 passed, 1 total
Tests: 1 passed, 1 total
Snapshots: 0 total
Time: 0.519 s
Ran all test suites.
✨ Done in 1.02s.可以看到对应的测试文件、分组以及测试覆盖率
路径映射
上面在测试代码时会先引入对应的工具代码如果都使用相对路径引入会显得很麻烦。在项目中通常都喜欢使用这种方式引入文件在测试环境依然可以使用这样也可以和项目中的文件路径保持一致
配置路径映射需要满足两个条件
jest识别路径映射ts识别路径映射如果项目中用了ts
配置jest路径映射
// jest.config.ts
{moduleNameMapper: {/(.*): rootDir/src/$1,},
}配置tsconfig
// tsconfig.json
{paths: {/*: [src/*]}
}这样在测试文件中就可以使用路径映射降低心智负担
// __tests__/demo.spec.ts
import { sum } from /utils;除了手动设置外还可以将tsconfig中的path直接作为路径映射这样就减少了多处的修改。实现这一功能需要借助ts-jest工具包不同这个自己也可以写个逻辑实现
// jest.config.ts
const { pathsToModuleNameMapper } require(ts-jest/utils)
const { compilerOptions } require(./tsconfig)export default {moduleNameMapper: pathsToModuleNameMapper(compilerOptions.paths, {prefix: rootDir/,}),
}dom测试
jest支持浏览器环境使用浏览器环境时需要安装对应的包请根据版本可以选择jsdom或jest-environment-jsdom包进行安装这里jest版本为28使用后者。测试文件修改如下
// __tests__/demo.spec.ts
describe(第一个测试, () {it(分组1, () {// 使用 localStorage APIlocalStorage.setItem(a, 1);expect(localStorage.getItem((a))).toBe(1)});
});运行测试用例
➜ npm run test
PASS __tests__/demo.spec.ts第一个测试✓ 分组1 (2 ms)----------|---------|----------|---------|---------|-------------------
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: 0.701 s, estimated 1 s
Ran all test suites.
✨ Done in 1.13s.异步测试
jest可以使用多种方式进行异步代码测试通常使用promise、async就可以了
使用promiseasync/await回调
这里模拟一个异步方法通过上面的三种方式进行测试
// src/utils
export function getUser(name: string) {return new Promise((resolve) {setTimeout(() resolve(name), 1000);});
}使用Promise
// __tests__/demo.spec.ts
import { getUser } from /utils;describe(测试异步代码, () {it(promise调用方式测试, () {const user 小明;// 使用thengetUser(user).then((res) {expect(res).toBe(user);});});it(使用resolves测试promise, () {const user 小李;// 使用 .resolves 方式注意这里要 returnreturn expect(getUser(user)).resolves.toBe(user);})
});使用async测试
// __tests__/demo.spec.ts
import { getUser } from /utils;describe(测试异步代码, () {it(使用async测试, async () {const user 小明;const res await getUser(user)expect(res).toBe(user);})
});使用回调函数
回调函数默认通常是以前那种回调写法这里需要对以上的异步函数进行调整让其换成回调函数模式
// 接受一个cb这里固定返回的值为true没有错误
export function getUser(cb: (error: any, data: any) void) {setTimeout(() {cb(null, true);}, 500);
}// 定义测试
describe(测试异步代码, () {it(使用回调函数, (done) {function cb(error: any, data: any) {if (error) {done(error);return;}try {expect(data).toBe(true);done();} catch (err) {done(err); // 这里一定要使用try catch防止出错时没有执行done}}getUser(cb);});
});回调模式一定要执行done函数如果没有执行则会被认为超时错误
模拟函数
假设要模拟一个工具函数的内部实现可以使用mock函数来判断函数内部的值是否达到预期
定义个待测试的函数forEach
export function forEach(items: number[], callback: (num: number) void) {for (let index 0; index items.length; index) {callback(items[index]);}
}添加测试用例
// __tests__/demo.spec.ts
import { forEach } from /utils;// 模拟函数
const mockFn jest.fn((x: number) x 1);test(模拟函数, () {forEach([0, 1], mockFn);expect(mockFn.mock.calls).toHaveLength(2);expect(mockFn.mock.calls[0][0]).toBe(0);expect(mockFn.mock.calls[1][0]).toBe(1);expect(mockFn.mock.results[0].value).toBe(1);
});更多关于模拟函数的例子请查看文档 和 API
定时器
Jest可以通过一个函数转换计时器以便允许你控制时间流量
假设测试如下定时器代码
export function useTimer(cb?: Function) {setTimeout(() cb cb(), 1000);
}编写测试用例
import { useTimer } from /utils;jest.useFakeTimers();
jest.spyOn(global, setTimeout);test(test timer, () {const cb jest.fn();useTimer(cb);expect(cb).not.toBeCalled();// 执行所有的定时器jest.runAllTimers();expect(cb).toBeCalled();
});更多见官方文档
setup配置
写测试的时候你经常需要在运行测试前做一些准备工作和在运行测试后进行一些收尾工作。 Jest 提供辅助函数来处理这个问题
这其中包括beforeEach、afterEach、beforeAll、afterAll其中前两者在每个测试前都会执行一次后者在文件中只会执行一次
覆盖率
除了对程序进行断言外jest还收集代码的测试覆盖率并生成对应的报告包括某个函数内部的测试覆盖率、整个文件的覆盖率要想达到覆盖率100%就要测试到每个文件的所有代码、每个函数内部的所有分支条件
开启覆盖率
可以通过配置文件
// jest.config.ts
// 主要涉及到这两个配置
export default {collectCoverage: true, // 启用coverageDirectory: coverage, // 报告生成位置
}通过cli执行脚本时带上参数
➜ npx jest --coverage测试覆盖率
假设我们有这么一个函数
export function whatType(arg: any) {const type Object.prototype.toString.call(arg)if (type [object String]) {return string;} else if (type [object Boolean]) {return boolean;}
}添加测试用例
import { whatType } from /utils;describe(测试覆盖率, () {it(函数条件覆盖率, () {expect(whatType(true)).toBe(boolean);});
});执行测试用例
➜ npm run testPASS __tests__/demo.spec.ts测试覆盖率✓ 函数条件覆盖率 (1 ms)----------|---------|----------|---------|---------|-------------------
File | % Stmts | % Branch | % Funcs | % Lines | Uncovered Line #s
----------|---------|----------|---------|---------|-------------------
All files | 96.77 | 50 | 100 | 96.77 | index.ts | 96.77 | 50 | 100 | 96.77 | 4
----------|---------|----------|---------|---------|-------------------
Test Suites: 1 passed, 1 total
Tests: 1 passed, 1 total
Snapshots: 0 total
Time: 0.486 s, estimated 1 sFile测试的文件Stmts测试中被执行的代码语句的比例Branch测试代码条件分支比例Funcs测试中被执行函数比例Lines测试中被执行代码行数比例Uncovered Line没有测试到的行数
除了查看终端的表格外还可以使用更直观的报告文件报告的结构大概如下
coverage
├── clover.xml # xml格式
├── coverage-final.json # json格式
├── lcov-report # html格式
│ ├── base.css
│ ├── block-navigation.js
│ ├── favicon.png
│ ├── index.html # 主页面入口
│ ├── index.ts.html
│ ├── other.ts.html
│ ├── prettify.css
│ ├── prettify.js
│ ├── sort-arrow-sprite.png
│ └── sorter.js
└── lcov.info一般都来查看HTML报告打开报告页面 可以点击对应的文件查看更详细的报告 Vue组件测试
jest也可以对vue组件进行测试vue官方提供了 vue2版本工具包(vue-test) 和 vue3版本工具包(vue/test-utils)这里基于vue3组件进行测试
安装对应的依赖
➜ npm install vue/test-utils -D对于Jestv28以上版本还需要添加以下配置
// jest.config.ts
export default {testEnvironmentOptions: {customExportConditions: [node, node-addons],},
}创建一个简单的Button组件
import { defineComponent } from vue;export default defineComponent({render(){return button按钮/button}
})添加测试用例
import { mount } from vue/test-utils;
import Button from /components/Button;test(测试vue组件, () {const wrapper mount({setup() {return () {return Button /;};},});expect(wrapper.text()).toBe(按钮)
})运行测试
➜ npm run testPASS __tests__/demo.spec.tsx✓ 测试vue组件 (9 ms)------------|---------|----------|---------|---------|-------------------
File | % Stmts | % Branch | % Funcs | % Lines | Uncovered Line #s
------------|---------|----------|---------|---------|-------------------
All files | 100 | 100 | 100 | 100 | Button.tsx | 100 | 100 | 100 | 100 |
------------|---------|----------|---------|---------|-------------------
Test Suites: 1 passed, 1 total
Tests: 1 passed, 1 total
Snapshots: 0 total
Time: 0.633 s添加全局组件当单测某个组件时组件内部引用的其它组件会因为没有引用而报错定义全局组件可以解决这个问题
// jest.setup.ts
import { config } from vue/test-utils;
import Button from /button/src/button;
import Icon from /button/src/icon;config.global.components {Button,Icon,
};配置jest
// jest.config.ts
export default {setupFiles: [rootDir/jest.setup.ts],
}这里不对vue工具包API过多的解释更多的API使用可以查看官方文档vue2版本的可以查看这里 由于格式和图片解析问题可前往 阅读原文