• 作者:老汪软件技巧
  • 发表时间:2024-12-02 21:06
  • 浏览量:

Vitest

看标题,没错,本次测试用到的是Vitest,为什么选择Vitest而不是Jest,首先,如果看Vitest的文档是可以看到Vitest是兼容Jest的API,另外一个重要的原因就是,Vite和Vitest本来就可以看作一家人,只是分工不同,官方大大是这样说的:Vitest 旨在将自己定位为 Vite 项目的首选测试框架,即使对于不使用 Vite 的项目也是一个可靠的替代方案

为什么要测试

你可能会问,为什么我们要花时间和精力去学习和编写测试呢?尤其是在接触测试的时候,确实会让人感到复杂且难以掌握。毕竟,直接引入组件并手动测试,或者通过控制台打印来调试工具函数,似乎更简单直接。那么,为什么我们还需要专门学习如何编写自动化测试呢?

1.随着项目规模的增长,手动测试变得不切实际

当你刚开始开发一个简单的组件时,比如 Button.vue,属性不多,功能也不复杂,手动测试可能确实是一个可行的选择。你可以逐个检查每个属性的行为,确保一切正常。但是,随着项目的不断扩展,组件的属性越来越多,功能也变得更加复杂。此时,手动测试的效率会大大降低,甚至可能出现遗漏的情况。

2.自动化测试提高了开发效率

自动化测试可以大幅提高开发效率。通过编写测试用例,你可以让计算机自动执行这些测试,而不需要每次都手动点击、输入和检查结果。这不仅节省了时间,还能确保每次代码更改后,所有功能都能正常工作。

3.测试是代码质量的保障

编写测试不仅是为了解决当前的问题,更是为了确保代码的长期可维护性和稳定性。良好的测试覆盖率可以让你的代码更具健壮性,减少潜在的错误和漏洞。

4.测试帮助你更好地设计代码

编写测试的过程不仅仅是验证代码是否正确,它还可以帮助你更好地设计代码。通过编写测试,你可以更清晰地思考组件的接口、行为和边界条件。这种“测试驱动开发”(TDD)的方法可以让你写出更加简洁、易于维护的代码。

测试Button组件

下载Vitest

npm install -D vitest

我们这里使用的是Vue,所以还要下载基于Vue的测试工具,显然Vitest肯定不是只能测试基于Vite构建或使用Vue框架相关的项目

下载vue-test-utils

npm install -D @vue/test-utils

Vitest 配置

安装完 Vitest 后,根文件夹中添加vitest.config.js文件中:

/// >
// 上面这行是 TypeScript 的三斜杠指令,用于引用 `vitest` 的类型定义。它确保我们在编写测试时可以使用 Vitest 提供的全局 API(如 `describe``test``expect` 等),并且获得正确的类型提示。
import { defineConfig } from "vite";
// 从 Vite 中导入 `defineConfig` 函数,用于定义 Vite 的配置对象。Vite 是一个现代的构建工具,支持快速开发和高效的生产构建。
import vue from "@vitejs/plugin-vue";
// 导入 Vite 的 Vue 插件,该插件用于处理 `.vue` 文件,支持单文件组件(SFC)的编译和热更新。
import vueJsx from "@vitejs/plugin-vue-jsx";
// 导入 Vite 的 Vue JSX 插件,该插件允许在 Vue 组件中使用 JSX 语法,适用于需要 JSX 支持的项目。
import VueMacros from "unplugin-vue-macros";
// 导入 `unplugin-vue-macros`,这是一个增强 Vue 开发体验的插件。它提供了多个宏(如 `defineComponent``setup` 等),简化了 Vue 组件的编写,并且与其他工具(如 Vite 和 Vue-Test-Utils)兼容。
// Vite 配置对象,用于定义项目的构建和开发环境设置
export default defineConfig({
  plugins: [
    // 使用 `VueMacros.vite` 来配置 Vite 插件链。`VueMacros` 是一个元插件,它可以自动加载并配置其他插件(如 `vue``vueJsx`),并且提供额外的功能。
    VueMacros.vite({
      plugins: {
        // 配置 Vue 插件,处理 `.vue` 文件
        vue: vue(),
        // 配置 Vue JSX 插件,支持 JSX 语法
        vueJsx: vueJsx(),
      },
    }),
  ],
  test: {
    globals: true, // 启用全局模式,使得 Vitest 的全局 API(如 `describe``test``expect` 等)可以直接在测试文件中使用,而不需要显式导入。
    environment: "jsdom", // 指定测试环境为 `jsdom`,这是一个虚拟的 DOM 实现,适用于浏览器环境的测试。`jsdom` 可以模拟浏览器的行为,使得我们可以测试与 DOM 相关的功能,而不需要实际打开浏览器。
  },
});

开始测试

// Button.test.ts
import { describe, test, expect } from "vitest";
import { mount } from "@vue/test-utils";
import Button from "./Button.vue";
import { FontAwesomeIcon } from "@fortawesome/vue-fontawesome";
import Icon from "../Icon/Icon.vue";
// 使用 vitest 的 describe 函数来定义测试套件,测试 Button.vue 组件
describe("Button.vue", () => {
  // 测试基础按钮的功能
  test("basic button", () => {
    // 使用 mount 函数挂载 Button 组件,并传递 props 和 slots
    const wrapper = mount(Button, {
      props: {
        type: "primary", // 设置按钮类型为 "primary"
      },
      slots: {
        default: "button", // 设置默认插槽内容为 "button"
      },
    });
    // 打印组件的 HTML 结构,用于调试
    console.log(wrapper.html());
    // 检查按钮是否具有预期的类名 "jd-button--primary"
    expect(wrapper.classes()).toContain("jd-button--primary");
    // 检查按钮的文本内容是否为 "button"
    expect(wrapper.get("button").text()).toBe("button");
    // 检查页面中只有一个按钮元素
    expect(wrapper.findAll("button").length).toBe(1);
    // 触发按钮的点击事件
    wrapper.get("button").trigger("click");
    // 检查按钮是否触发了 "click" 事件
    expect(wrapper.emitted()).toHaveProperty("click");
  });

组件测试的任务__写组件库

// 测试禁用按钮的功能 test("disabled button", () => { // 挂载 Button 组件,并设置 disabled 属性为 true const wrapper = mount(Button, { props: { disabled: true, }, slots: { default: "button", }, }); // 检查按钮是否具有 "disabled" 属性 expect(wrapper.get("button").attributes("disabled")).toBeDefined(); // 触发禁用按钮的点击事件 wrapper.get("button").trigger("click"); // 检查禁用按钮是否没有触发 "click" 事件 expect(wrapper.emitted()).not.toHaveProperty("click"); }); // 测试带有图标的按钮 test("icon", () => { // 挂载 Button 组件,并设置 icon 属性为 "search" const wrapper = mount(Button, { props: { icon: "search", }, slots: { default: "button", }, global: { stubs: ["FontAwesomeIcon"], // 模拟第三方组件 FontAwesomeIcon }, }); // 检查按钮内部是否存在 FontAwesomeIcon 组件 const icon = wrapper.findComponent(FontAwesomeIcon); expect(icon.exists()).toBe(true); // 检查图标组件的 icon 属性是否为 "search" expect(icon.props("icon")).toBe("search"); }); // 测试加载中的按钮 test("loading", () => { // 挂载 Button 组件,并设置 loading 属性为 true const wrapper = mount(Button, { props: { loading: true, }, slots: { default: "loading", }, global: { stubs: ["Icon"], // 模拟本地的 Icon 组件 }, }); // 打印组件的 HTML 结构,用于调试 console.log(wrapper.html()); // 检查按钮是否具有 "is-loading" 类名 expect(wrapper.get("button").classes()).toContain("is-loading"); // 检查按钮的文本内容是否为 "loading" expect(wrapper.get("button").text()).toBe("loading"); // 检查按钮内部是否存在 Icon 组件 const icon = wrapper.findComponent(Icon); expect(icon.exists()).toBe(true); // 检查图标组件的 icon 属性是否为 "spinner" expect(icon.props("icon")).toBe("spinner"); // 检查按钮是否具有 "disabled" 属性 expect(wrapper.attributes("disabled")).toBeDefined(); }); });

启动测试,Button就是测试代码所在的文件名 => Button.test.ts

npx vitest Button

测试结果如下:

image.png

可以看到生成了button节点且测试内容均生效

至于测试中使用到的函数及方法,这里简单介绍下:

describe:

test:

expect:

mount:

测试的重要性

所以看到这里应该知道测试的重要性了:

总结

使用 Vitest 对我们的应用程序进行单元测试是无缝的,与Jest等替代品相比,需要更少的步骤来启动和运行。Vitest 还可以很容易地将现有的测试从 Jest 迁移到Vitest,而不需要进行额外的配置。


上一条查看详情 +重拾js-浏览器JS对象
下一条 查看详情 +没有了