单元测试之 Vitest 进行组件测试

常用的测试方案大致分为有 4 种:

  • 端对端测试:利用一个很像用户行为的机器人来和 App 交互,并验证功能是否正常。有时也会说 “功能测试” 或 E2E。
  • 集成测试:验证多个单元是否能协调共同工作。
  • 单元测试:验证单独隔离的部分是否正常工作。
  • 静态测试:捕获写代码时的错别字和类型错误

Vitest 与 Jest 兼容,具有开箱即用的 ESM、Typescript 和 JSX 支持,并且由 esbuild 提供支持。它在测试过程中使用 Vite 开发服务器来转换你的文件,并监听你的应用程序的相同配置(通过vite.config.js),从而消除了使用Jest等测试替代品所涉及的重复工作。

官网

image.png

为什么要进行单元测试?

  • 验证功能:单元测试确保代码做正确的事情并且不做任何不应该做的事情——大多数错误发生在这里。
  • 防止代码回归:当我们发现错误时,添加单元测试来检查场景可以防止代码更改在将来重新引入错误。
  • 记录代码:通过正确的单元测试,一套完整的测试和结果提供了应用程序应该如何工作的规范。
  • 保护您的应用程序:单元测试可以检查可利用的漏洞(例如启用恶意 SQL 注入的漏洞)。

如何使用 Vitest 来测试组件

pnpm add -D vitest

or
npm install -D vitest
or
yarn add -D vitest

配置 Vitest

Vitest 的主要优势之一是它与 Vite 的统一配置。如果存在,vitest 将读取你的根目录 vite.config.ts 以匹配插件并设置为你的 Vite 应用程序。例如,你的 Vite 有 resolve.aliasplugins 的配置将会在 Vitest 中开箱即用。如果你想在测试期间想要不同的配置,你可以:

  • 创建 vitest.config.ts,优先级将会最高。
  • --config 选项传递给 CLI,例如 vitest --config ./path/to/vitest.config.ts
  • defineConfig 上使用 process.env.VITESTmode 属性(如果没有被覆盖,将设置为 test)有条件地在 vite.config.ts 中应用不同的配置。

如果你已经在使用 Vite,请在 Vite 配置中添加 test 属性。你还需要使用 三斜杠指令 在你的配置文件的顶部引用。

Vitest 提供 environment 选项以在特定环境中运行代码,可以使用 environmentOptions 选项修改环境的行为方式。默认情况下,可以使用这些环境:

  • node 为默认环境
  • jsdom 通过提供 Browser API 模拟浏览器环境,使用 jsdom
  • happy-dom 通过提供 Browser API 模拟浏览器环境,被认为比 jsdom 更快,但缺少一些 API,使用 happy-dom
// <reference types="vitest" />
import { defineConfig } from 'vite'

export default defineConfig({
  test: {
            environment: "happy-dom"
  },
})

事例演示 Button

image.png

应该测试什么?

思考这个组件需要做什么,以达到预期的功能。

测试依赖项

有时我们需要个根元素, 类似‘#app’一样的挂载点,我们需要访问Vue Test Utils的mount方法,这是Vue.js的官方测试工具库

常见的Vitest方法

describe:这个函数接受一个名字和一个函数,用于将相关的测试组合在一起。当你为一个有多个测试点(如逻辑和外观)的组件编写测试时,它就会很方便。

test/it:这个函数代表被测试的实际代码块。它接受一个字符串,通常是测试案例的名称或描述(例如,渲染成功的正确样式)和另一个函数,所有的检查和测试在这里进行。

expect: 这个函数用于测试值或创建断言。它接受一个预期为实际值(字符串、数字、对象等)的参数x,并使用任何支持的方法对其进行评估(例如toEqual(y),检查 x 是否与 y 相同)。

toContain:toContain 断言实际值是否在数组中。toContain 还可以检查一个字符串是否是另一个字符串的子串。自 Vitest 1.0 起,如果我们需要在类似浏览器的环境中运行测试,此断言还可以检查类是否包含在 classList 中,或一个元素是否包含在另一个元素中。

测试button 组件 button.test.ts

import { describe, expect, it } from "vitest";
import { mount } from '@vue/test-utils'
import button from '../button.vue'
// The component to test


describe('test Button', () => {
    it("should render slot", () => {
        const wrapper = mount(button, {
            slots: {
                default: 'Hello world'
            }
        })

        // Assert the rendered text of the component
        expect(wrapper.text()).toContain('Hello world')
    })
    it("should have class", () => {
        const wrapper = mount(button, {
            props: {
                type: 'primary'
            }
        })
        expect(wrapper.classes()).toContain('k-button--primary')
    })
})

运行测试

pnpm run test
由于Vitest的智能和即时观察模式,这个命令只需要运行一次,并在我们对测试文件进行更新和修改时被重新运行。

  "scripts": {
    "test": "pnpm run --filter ./packages/components test",
    "coverage": "pnpm run --filter ./packages/components coverage"
  },

失败给出对应的提示

image.png

通过的提示

image.png

查看覆盖率

最后我们可以执行pnpm run coverage or pnpm -w run coverage来查看我们测试的覆盖情况


image.png

%stmts是语句覆盖率(statement coverage):是不是每个语句都执行了?

%Branch分支覆盖率(branch coverage):是不是每个if代码块都执行了?

%Funcs函数覆盖率(function coverage):是不是每个函数都调用了?

%Lines行覆盖率(line coverage):是不是每一行都执行了?

总结

再写单测的时候思考 组件 或 方法的正确性

©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容