English 简体中文 繁體中文 한국 사람 日本語 Deutsch русский بالعربية TÜRKÇE português คนไทย french
查看: 3|回复: 0

试试使用 Vitest 进行测试,确实可以减少bug

[复制链接]
查看: 3|回复: 0

试试使用 Vitest 进行测试,确实可以减少bug

[复制链接]
查看: 3|回复: 0

224

主题

0

回帖

682

积分

高级会员

积分
682
eq1E5BLQZw7W

224

主题

0

回帖

682

积分

高级会员

积分
682
2025-2-28 22:48:30 | 显示全部楼层 |阅读模式

vitest的简单介绍

Vitest 是一个基于 Vite 的单元测试框架,专为现代前端项目设计。
它结合了 Vite 的高性能和 Jest 的易用性,
提供了开箱即用的 TypeScript、ESM 和 JSX 支持,同时与 Vite 的配置无缝集成。
安装vitest

npm install -D vitest
vite.config.js中配置vitest

/// <reference types="vitest" /> // 上面的这个是必须要写的,你需要注意一下,别漏掉了import vue from '@vitejs/plugin-vue'// https://vite.dev/config/export default defineConfig({  plugins: [vue()],  base: './', //生产环境相对目录部署  server: {    open:true, //自动打开浏览器    host: '0.0.0.0', //通过ip的形式访问    cors: true, // 启用 CORS (boolean) 可以访问任何源上的资源    force: true, // 强制优化器忽略缓存并重新构建 (boolean)    clearScreen: false, // 允许或禁用打印日志时清除屏幕  (boolean)  },  // 新增 vitest配置  test:{    environment: 'happy-dom', // 表示测试环境  }})happy-dom

首先我们要安装 npm i happy-dom -D
因为我们后面的测试需要依赖它。
happy-dom:完整的 Web 浏览器环境。
包括 DOM 解析、CSS 渲染和 JavaScript 执行等核心模块。
但剥离了图形用户界面(GUI)的依赖‌
// package.json 文件"scripts": {    "dev": "vite",    "build": "vite build",    "preview": "vite preview",    // 新增下面这2行    "test": "vitest",    "coverage": "vitest run --coverage"  },我们等会使用 npm test命令就可以测试啦

测试2个数相加,使用toBe来比较值

// src\test\index.spec.js 需要你创建import { describe, it,expect } from "vitest"/** * describe中的第1个参数: first test 表示的是测试标题 * 第2个参数:表示的是测试的内容 * */ describe("first test", () => {  it("should is 2", () => {    // 表示测试的内容 expect(1+2), toBe(2)等于2    expect(1+2).toBe(3)  })})执行 npm test

比较返回来的值是否符合预期,使用

// src\utils\common.js 公共文件// 找出小于18岁的人的信息export function getNoAdultPerson(dataObj){  // 不影响原始数据  let dataNewObj = JSON.parse(JSON.stringify(dataObj));  // 收集要删除的属性名  let keysToDelete = [];  for (let key in dataNewObj) {    if (dataNewObj.hasOwnProperty(key) && dataNewObj[key].age >=18) {      keysToDelete.push(key);    }  }  // 删除收集到的属性  keysToDelete.forEach(key => {    delete dataNewObj[key];  });  return dataNewObj;}<template>  <div>    <h1 class="main">下面是数据</h1>    {{ data }}  </div></template><script setup>import { getNoAdultPerson } from '../../utils/common.js';import { ref } from 'vue';let obj= {  "zhansan": {    user: "zhansan",    age: 14  },  "lisi": {    user: "lisi",    age: 26  }}let data = getNoAdultPerson(obj)</script>// src\test\index.spec.js 测试文件import { describe, it,expect } from "vitest"import { getNoAdultPerson } from "../utils/common.js"// 这个测试用例是找出age<18的用户的信息describe("second test", () => {  const writeData= {    "zhansan": {      user: "zhansan",      age: 14    },    "lisi": {      user: "lisi",      age: 26    }  }  const expectData = { "zhansan": { "user": "zhansan", "age": 14 } }  it("test adult", () => {    // 这里必须要使用toEqual,不能够使用toBe    expect(getNoAdultPerson(writeData)).toEqual(expectData)  })})执行 npm test

toBe 和 toEqual 的区别

toEqual 通常用于比较对象或数组的值是否相等,而不是检查它们是否是同一个实例。
比如:两个不同的对象,如果属性值都相同。用toEqual会通过,而toBe不会。
toBe检查的是严格相等,即对象引用是否相同。通常用来比较简单数据类型或实例是否相等
验证:toBe检查的是严格相等,即对象引用是否相同

import { describe, it,expect } from "vitest"let obj1 = { a: 1, b: 2 }let obj2 = { a: 1, b: 2 }describe("test toBe", () => {  it("yan zheng toBe", () => {    // 因为 obj1 和 obj2 是两个不同的对象,所以它们不相等,所以测试用例会失败    expect(obj1).toBe(obj2)  })})如果我们想要让 obj1等于obj2,我们可以使用 toEqual。
因为:toEqual 只会比较对象中的值是否相等,而不会比较是否是同一个实例。

vue组件测试

如果需要对组件进行测试,我们需要借助 Vue Test Utils
它的地址:https://test-utils.vuejs.org/guide/
Vue Test Utils 1 适用于 Vue 2。
Vue Test Utils 2 使用于 Vue 3。
首先需要安装:npm install --save-dev @vue/test-utils
其他知识点:
yarn add = npm i
--save-dev 等价与-D
测试组件的内容 slot

ListCard.vue文件,是一个组件
<template>  <div>    <h1>{{ titleName }}</h1>    <main>      <slot />    </main>    <footer>      Thanks for visiting.    </footer>  </div></template><script setup>import {defineProps} from 'vue'defineProps({  titleName:{    type: String,    default: '我是默认值'  }})</script>下面是单元测试的文件
import { describe, it,expect } from "vitest";import { mount } from "@vue/test-utils"import listCard from "./ListCard.vue"describe ('listCard test', () => {  it('test demo1', () => {    const listDemo = mount(listCard,{      slots:{        default: '张三的详细信息'      }    })    console.log('输出的值:',listDemo.text())    expect(listDemo.text()).toContain('Thanks')  })})
toContain的简单介绍

toContain() 是一个断言匹配器,它的作用是检查某个值是否包含指定的子字符串、数组元素、集合成员。
// 检查数组是否包含元素expect([1, 2, 3]).toContain(2) // 通过// 检查 Set 是否包含值expect(new Set([1, 2, 3])).toContain(3) // 通过// 检查长字符串包含子串expect('Hello World').toContain('llo W') // 通过测试某一个标签中的具体内容

<template>  <div>    <h1 class="head-title">{{ titleName }}</h1>    <h1>我也是表退</h1>    <main>      <slot />    </main>    <footer>      Thanks for visiting.    </footer>    <h1 class="footer-title"></h1>  </div></template><script setup>import {defineProps} from 'vue'defineProps({  titleName:{    type: String,    default: '我是默认值'  }})</script>import { describe, it,expect } from "vitest";import { mount } from "@vue/test-utils"import listCard from "./ListCard.vue"describe ('测试组件', () => {  it('测试某一个具体元素的文本', () => {    const listDemo = mount(listCard)    // 查询组件中类名是head-title的标签,并获取标签中的文本内容,    expect(listDemo.find('[class="head-title"]').text()).toBe('我是默认值')  })})测试组件中的插槽

现在我们想去验证 main 元素中的的插槽是否正确。
我们需要在mount中的去设置插槽
验证插槽是否存在,通过exists来进行判断的哈。
然后再通过 toContain验证是否包含我们设置的html元素。
<template>  <div>    <h1 class="head-title">{{ titleName }}</h1>    <h1>{{ titleName }}</h1>    <h1  tef="headTitle">我也是表退</h1>    <main>      <slot />    </main>    <footer>      Thanks for visiting.    </footer>    <h1 class="footer-title"></h1>  </div></template><script setup>import {defineProps} from 'vue'defineProps({  titleName:{    type: String,    default: '我是默认值'  }})</script>import { describe, it,expect } from "vitest";import { mount } from "@vue/test-utils"import listCard from "./ListCard.vue"describe ('测试组件', () => {  it('测试组件的插槽', () => {    // slotContent 也可以等于一个组件,这个组件需要我们引入进来。下面是一个html,也相当于一个组件    const slotContent = `<div data-test="slot-content">我是插槽-</div>`    // 给这个组件放置插槽    const listDemo = mount(listCard,{      slots: { default: slotContent }    })    // 验证插槽是否存在    expect(listDemo.find('[data-test="slot-content"]').exists()).toBe(true)    // 验证插槽中的html内容,验证html内容一般使用toContain    expect(listDemo.find('main').html()).toContain(slotContent)  })})测试超长标题并显示省略号

<template>  <div>    <h1 class="head-title">{{ titleName }}</h1>    <h1  tef="headTitle">我也是表退</h1>    <main>      <slot />    </main>    <footer>      Thanks for visiting.    </footer>    <h1 class="footer-title"></h1>  </div></template><script setup>import {defineProps} from 'vue'defineProps({  titleName:{    type: String,    default: '我是默认值'  }})</script><style scoped>.head-title{  white-space: nowrap; /* 防止文本换行 */  overflow: hidden; /* 隐藏溢出的文本 */  text-overflow: ellipsis; /* 显示省略号 */  width: 50%; }</style>import { describe, it,expect } from "vitest";import { mount } from "@vue/test-utils"import listCard from "./ListCard.vue"describe ('测试组件', () => {  it('应处理超长标题并显示省略号', () => {    const longTitle = '日照香炉生紫烟,遥看瀑布挂前川。飞流直下三千尺,疑是银河落九天。标签: 小学古诗写景庐山景色瀑布山水数字出自部编版二年级上《古诗二首》';    const listDemo = mount(listCard, {      props: { titleName: longTitle }    });    // 获取class="head-title这个元素的文本内容,并判断是否包含省略号    expect(listDemo.find('class="head-title"').text()).toContain('...');  });})查看单元测试的覆盖率

在package.json中,我们会在 scripts 下看见
"coverage": "vitest run --coverage"
这条命令可以查看单元测试的覆盖率
然后执行:npm run coverage
如果没有安装 @vitest/coverage-v8的话
会有下面的提示信息:
? Do you want to install @vitest/coverage-v8?  » (y/N)
我们输入y,然后回车,就会自动安装。
安装成功之后,我们再次执行:npm run coverage
{  "name": "studyvite5",  "private": true,  "version": "0.0.0",  "type": "module",  "scripts": {    "dev": "vite",    "build": "vite build",    "preview": "vite preview",    "test": "vitest",    // 查看单元测试的覆盖率的配置    "coverage": "vitest run --coverage"  }}

%Stmts, %Branch, %Funcs,%Lines, Uncovered Line的意思

%Stmts(语句覆盖率):测试覆盖了多少比例的代码语句。
%Branch(分支覆盖率):测试覆盖了多少比例的条件分支(如 if/else 语句的两个分支)
%Funcs(函数覆盖率):测试覆盖了多少比例的函数或方法。
%Lines(行覆盖率):测试覆盖了多少比例的代码行。
Uncovered Line #s(未覆盖的行号):具体哪些代码行未被测试覆盖
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

224

主题

0

回帖

682

积分

高级会员

积分
682

QQ|智能设备 | 粤ICP备2024353841号-1

GMT+8, 2025-3-11 03:06 , Processed in 2.443144 second(s), 29 queries .

Powered by 智能设备

©2025

|网站地图