自动化测试是指 使用独立于待测软件的其他软件或程序来自动执行测试,比较实际结果与预期 并生成测试报告这一过程。在测试流程已经确定后,测试自动化可以自动执行的一些重复性但必要的测试工作。也可以完成手动测试几乎不可能完成的测试。
1. 基于图形用户交互界面测试
基于用户界面(GUI)的测试使用能够产生图形用户界面操作(如出表点击、键盘输入等)的测试框架,模拟用户动作来以观察、验证程序是否正确的响应。
2. 接口测试
接口测试指的是通过调用接口(API)绕过GUI层,以 API 应用验证行为进行测试。通常API 绕过测试的应用程序的用户界面。它也可以测试 公共(通常)的接口 ,用各种各样的输入参数来验证返回的结果是正确的。
1、单元测试的用例可以在代码编写完成之前就设计好,并作为功能的一种定义形式存在。随着新的代码不断完成编写,单元测试随之进行,缺陷被不断找出,因而代码也不断得到改进。
2、手工完成一些软件测试的工作(例如大量的低级接口的回归测试)十分艰苦耗时, 而且寻找某些种类的缺陷时效率并不高,因而测试自动化,提供一种完成这类工作的有效方法。
3、一旦自动化测试方法开发完成,日后的测试工作将可以高效循环完成。很多时候这是针对软件产品进行长期回归测试的高效方法。毕竟早期一个微小的补丁中引入的回归问题可能在日后导致巨大的损失。
1. 单元测试
把代码看成一个个组件,对每个组件进行单独测试,组件内每一个函数的返回结果(或者dom的结构)是不是和期望值一样。
2. e2e(端到端)测试
把程序当做黑盒子,以用户的视角对真实系统的访问行为进行仿真,对测试的输入(用户行为/模拟数据),看能否得到预期得到的结果。
vitest是由vite提供支持的下一代测试框架
该工具一开始就考虑到了vite,利用了在DX中的改进,例如即时热模块重新加载(HMR)
定位为vite项目的首选测试运行者,甚至对于不使用vite的项目来说也是一个可靠的替代方案
Jest
Vitest
cypress 定义
被称为端到端测试工具,其新组件测试运行期对测试vite有很大的支持,并且·是测试浏览器中呈现的内容的理想选择
?
是基于浏览器的测试运行期,是vite的补充工具,将捕获vitest无法捕获的问题(因为其使用真实的浏览器和真实的浏览器api)
vitest定义
是基于节点的运行程序,专注于为闪电般的无头测试提供最佳DX,
cypress 功能
用于e2e和组件测试
其测试驱动恒旭专注于确定元素是否可见,可访问,交互,cypress专为UI开发和测试而构建,测试完成之后,您可以使用浏览器开发工具调试发生的任何故障
?
像IDE,您可以在浏览器中看到真实渲染的组件以及测试结果和日志
vitest 功能
用于单元测试(测试无头代码的好选择)
?
支持各种部分实现的浏览器环境,例如Jsdom,这些环境足以让您快速对引用浏览器api的任何代码进行单元测试,代价是这些浏览器环境在其可实现的功能方面存在限制,例如jsdom缺少很多功能(window.navigation,布局引擎offsetTop)
使用对应用程序中的所有无头逻辑使用vitest,对所有基于浏览器的逻辑使用cypress
?
安装:
pnpm install -D vitest
package.json配置
?"test:unit": "vitest --typecheck",
?运行模式,运行或者监听
vitest watch
? ? ? 监听模式 为执行vitest的默认模式
vitest run? ?运行模式
可以直接在当前的vite.config.ts文件中配置
/// <reference types="vitest" />
...
? test: {
? ? globals:true, // 是否全局引入
? ? environment:"happy-dom" // 环境选择?jsdom
? ? // include: ['test/**/*.test.ts'],
? ? // deps: {
? ? // ? inline: ['@vue', '@vueuse', 'element-plus', 'vue-i18n'],
? ? // },
? },
也可以单独创建一个vitest.config.ts文件,优先级高于vite.config.ts
import { fileURLToPath } from 'node:url'
import { mergeConfig, defineConfig, configDefaults } from 'vitest/config'
import viteConfig from './vite.config'
export default mergeConfig(
viteConfig,
defineConfig({
define: {
'import.meta.vitest': 'undefined', // 源码内联测试配置
},
test: {
// 启用基准测试模式
mode: 'benchmark',
// globals: true, // 全局引入vitest 位置一
environment: 'jsdom',
exclude: [...configDefaults.exclude, 'e2e/*'],
includeSource: ['src/**/*.{js,ts}'],
root: fileURLToPath(new URL('./', import.meta.url)),
coverage: {
provider: 'istanbul', // or 'v8' 默认使用v8
reporter: ['text', 'html', 'json'],
// reporters: ['verbose'],
reporters: ['html'],
// reportsDirectory: './tests/unit/coverage', // 修改输出报告位置
exclude:['src/**/icons'] //不需要单元测试覆盖的地方
},
// browser: {
// enabled: true,
// name: 'chrome', // browser name is required
// },
}
})
)
当只需要运行某个测试文件,或者包含某字符串的测试文件
$ vitest basic
将只执行包含?basic
?的测试文件,例如:
basic.test.ts
basic-foo.test.ts
basic/foo.test.ts
如果在测试套件中使用?.concurrent
,则其中的每个测试用例都将并发运行。
你还可以将?.skip(跳过)
、.only
?(仅执行这个)和?.todo
?(待完成)用于并发测试套件和测试用例。
sequential? 按顺序测试
fails?明确表示断言失败
运行并发测试时,快照和断言必须使用本地测试上下文中的?expect
,以确保检测到正确的测试。
test.concurrent("test 1", async ({ expect }) => {
? expect(foo).toMatchSnapshot();
});
test.concurrent("test 2", async ({ expect }) => {
? expect(foo).toMatchSnapshot();
});?
当希望确保函数的输出不会意外更改时,可以使用快照测试,兼容 Jest 快照测试。使用快照时,Vitest 将获取给定值的快照,将其比较时将参考存储在测试旁边的快照文件。如果两个快照不匹配,则测试将失败:要么更改是意外的,要么参考快照需要更新到测试结果的新版本。
// 此测试在第一次运行时,Vitest 会创建一个快照文件
expect(result).toMatchSnapshot()
// 内联快照? 这允许你直接查看期望输出,而无需跨不同的文件跳转。expect(result).toMatchInlineSnapshot(`"FOOBAR"`)
// 文件快照会以文件的方式存储 ?
await expect(result).toMatchFileSnapshot('../__snapshots__/HelloWorld1.json') // 文件保存路径
自动更新内联快照内容:
?npx vitest -u
执行 npm run vitest 命令 不会更新内联快照
?npx vitest --coverage 输出覆盖范围
Vitest 通过?v8(默认) 支持原生代码覆盖率,通过?istanbul?支持检测代码覆盖率。
// vitest.config.ts
import { defineConfig } from 'vitest/config'export default defineConfig({
? test: {
? ? coverage: {
? ? ? provider: 'istanbul', // or 'v8'
? ? },
? },
})
定义输出报告的格式
// vitest.config.ts
import { defineConfig } from 'vitest/config'export default defineConfig({
? test: {
? ? coverage: {
? ? ? reporter: ['text', 'json', 'html'],
? ? },
? },
})
这个属性定义了覆盖率报告的输出格式。这里指定了三种格式:文本、JSON 和 HTML。这意味着在运行测试时,Vitest 将生成并输出这三种格式的覆盖率报告。
// src/index.ts
// 函数实现
export function add(...args: number[]) {
? return args.reduce((a, b) => a + b, 0)
}// 源码内的测试套件
if (import.meta.vitest) {
? const { it, expect } = import.meta.vitest
? it('add', () => {
? ? expect(add()).toBe(0)
? ? expect(add(1)).toBe(1)
? ? expect(add(1, 2, 3)).toBe(6)
? })
}
更新配置文件
// vite.config.ts
/// <reference types="vitest" />
import { defineConfig } from 'vite'export default defineConfig({
?define: {
? ? 'import.meta.vitest': 'undefined', // 源码内联测试配置
? },
? test: {
? ? includeSource: ['src/**/*.{js,ts}'],?
? },
})
import { assertType, expectTypeOf ,test} from 'vitest'
import { mount } from '../../assets/common'
test('my types work properly', () => {
expectTypeOf(mount).toBeFunction()
expectTypeOf(mount).parameter(0).toMatchTypeOf<{ name: string }>() // 验证 mount 函数的第一个参数的类型是否为 { name: string }。
// @ts-expect-error name is a string // 这是一个注释,指示 TypeScript 在编译时应该期望一个错误,因为接下来的代码会尝试将一个非字符串值赋给 name。
assertType(mount({ name: 42 })) // 尝试调用 mount 函数并传递一个对象作为参数,其中 name 的值是 42(一个数字,而不是字符串)。由于前面的注释,TypeScript 应该期望这里有一个类型错误。
})
此功能可用于:
对于更复杂的测试,比如组件测试或 E2E 测试,建议使用单独的测试文件取而代之。
vitest 退出及时更新模式
npx vitest run
要重新打开Vitest的多线程功能,您需要移除
--no-threads
选项,然后再次运行测试。例如,如果您之前使用以下命令禁用了多线程:
vitest --no-threads
要重新打开多线程功能,只需运行以下命令:
vitest
这将重新启用Vitest的多线程功能,并允许测试并行运行以提高执行效率。
请注意,禁用多线程功能可能会降低测试的执行效率,因为测试将按顺序逐个执行,而不是并行运行。在大多数情况下,建议使用多线程功能来提高测试的执行效率。
assert(value, message)
:断言函数返回的值是否为真。如果断言失败,则抛出错误并显示提供的消息。toBe(value)
:断言函数返回的值是否严格等于给定的值。toBeCloseTo(value, precision)
:断言函数返回的值是否接近给定的值。precision 参数指定小数点后的位数。toBeDefined()
:断言函数返回的值是否已定义(不是 undefined)。toBeFalsy()
:断言函数返回的值是否为假值(false、null、undefined、0、NaN 或空字符串)。toBeGreaterThan(value)
:断言函数返回的值是否大于给定的值。toBeLessThan(value)
:断言函数返回的值是否小于给定的值。toBeNaN()
:断言函数返回的值是否为 NaN。toBeNull()
:断言函数返回的值是否为 null。toBeTruthy()
:断言函数返回的值是否为真值(true、非空对象、非零数字、非 NaN)。toBeUndefined()
:断言函数返回的值是否未定义(undefined)。toContain(element)
:断言函数返回的数组是否包含指定的元素。toEqual(value)
:断言函数返回的值是否与给定的值相等。toMatch(pattern)
:断言函数返回的值是否匹配正则表达式或字符串。
1、两种单元测试文件名.spec.ts文件和.test.ts的区别:
compose函数
const add1 = (x) => x + 1;
const mul3 = (x) => x * 3;
const div2 = (x) => x / 2;function compose(...funcs){
? ? return function anonymous(val){debugger;
? ? ? ? if(funcs.length===0) return val;
? ? ? ? if(funcs.length===1) return funcs[0](val);
? ? ? ? return funcs.reverse().reduce((N,item)=>{
? ? ? ? ? ? ? return item(N)
? ? ? ? },val)
? ? }
}compose(add1,mul3,div2)(3)