Vitest 让单元测试更简单一点

4,256 阅读6分钟

为什么选择 Vitest ?

一个是因为 Vitest 基于 Vite 并能重复使用 Vite 的配置、转换器、解析器和插件,以及开箱即用的 TypeScript / JSX 支持等特点把我的目光从 Jest 中夺了过去(翻译翻译就是它又快配置又简单,这种框架谁不喜欢呢?)

二个是因为作者是 Anthony Fu 大佬

官方地址留给你们后续查资料

上手指南从这里开始了啊

Vitest 安装

提示:Vitest 需要 Vite >=v3.0.0 和 Node >=v14

然后根据自己的项目选择其中一种安装方式就行,最好不要混用

npm install -D vitest

yarn add -D vitest

pnpm add -D vitest

执行完安装命令后,你的 package.json 文件中 devDependencies 下就会出现 "vitest": "^x.x.x",也代表你安装成功了!

Vitest 配置

Vitest 可以直接读取你的 vite.config.ts 文件,所以你其实并不需要单独建立 vitest.config.ts 文件了。

vite.config.ts 文件中,我们将 import { defineConfig } from "vite" 替换成 import { defineConfig } from "vitest/config",然后在配置中新增一个 test 属性就完成了写配置最基本的结构:

import { defineConfig } from "vitest/config"
export default defineConfig({
  test: { // ... }
})

假如你并不想替换 import { defineConfig } from "vite",或者你的项目根本没有用到 import { defineConfig } from "vite",这时候有没有其他办法呢?

答案当然是有的,你可以在 vite.config.ts 文件的最顶部(第一行)加上三斜线命令:/// <reference types="vitest" /> 即可!

我自己的项目就是采用的添加三斜线命令的方式来进行配置的:

/// <reference types="vitest" />
import { defineConfig } from "vite"
export default defineConfig({
  test: { // ... }
})

TS 配置

如果你的项目是基于 TypeScript 的,那么你还应该在 tsconfig.json 文件的 compilerOptions.types 配置中添加:"vitest""vitest/globals",如下:

{
  "compilerOptions": {
    "types": [
      "vitest",
      "vitest/globals"
    ]
  }
}

Vitest 运行

现在你需要在你的 package.json 文件中 scripts 下新增 "test": "vitest" 脚本:

{
  "scripts": {
    "test": "vitest"
  }
}

然后后续你要进行单元测试的时候,执行 npm run testyarn testpnpm test 命令就行了。

Vitest 语法

建立测试文件

可以去项目根目录建立一个名为 tests 的文件夹,然后在里面建立一个名为 demo.test.ts 的测试文件。其中 demo 是文件名称,.test.ts 是特殊的后缀。

维护 Vitest 配置

由于以后我们都会将测试文件放在 tests 文件夹下,所以我们可以将 Vitest 配置修改为:

test: {
  include: ["tests/**/*.test.ts"]
}

这代表 Vitest 将去 tests 文件夹下面寻找 .test.ts 后缀的测试文件。

编写测试用例

我们在 demo.test.ts 测试文件中写入如下测试代码:

import { describe, expect, it } from "vitest"

const author1 = {
  name: "pany",
  email: "939630029@qq.com",
  url: "https://github.com/pany-ang"
}

const author2 = {
  name: "pany",
  email: "939630029@qq.com",
  url: "https://github.com/pany-ang"
}

describe("这里填写作用域名称", () => {
  it("测试基础数据类型", () => {
    expect(1 + 1).toBe(2)
  })
  it("测试引用类型", () => {
    expect(author1).toEqual(author2)
  })
})

Vitest API 解释

  • describe:形成一个作用域
  • test/it:定义了一组关于测试期望的方法,它接收测试名称和一个含有测试期望的函数
  • expect:创建断言
  • toBe:可用于断言基础对象是否相等,或者对象是否共享相同的引用
  • toEqual:断言检查值是否等于接收值,或者是同样的结构,如果是对象类型(将会使用递归的方法进行比较)

执行命令测试

我们这时候执行 npm run testyarn testpnpm test 命令就可以得到该测试文件的测试结果,如下图:

image.png

代表通过测试。这时候我们去修改一下测试代码,将 expect(1 + 1).toBe(2) 修改为 expect(1 + 1).toBe(3),可以得到如下报错信息:

image.png

并且从报错信息中,我们可以清楚的定位到是测试基础数据类型这个用例发生了错误,然后通过 ExpectedReceived,也可以清楚看见结果值和预期值之间的差异。

Vitest 实战

我们用 Vitest 来测试 Vue 的组件,来模拟一下真实的单元测试。

维护 Vitest 配置

在上文中,我们已经将配置修改为:

test: {
  include: ["tests/**/*.test.ts"]
}

然后这里我们要将它再次修改为这样:

test: {
  include: ["tests/**/*.test.ts"],
  environment: "jsdom"
}

这代表着,我们将用 jsdom 这个库,在本地 Node 环境中模拟浏览器的 DOM 环境(因为我们要开始测 Vue 组件啦)

安装依赖

到这里我们要继续新增一些依赖,第一个就是上文提到的 jsdom,第二个是 @vue/test-utils

# 用 pnpm 命令举例安装
pnpm add -D jsdom
pnpm add -D @vue/test-utils

安装 @vue/test-utils 是因为 Vitest 本身是不支持 Vue 组件单元测试的,需要安装它来配合测试。

编写测试用例

假如我们要测试的组件名为 Notify.vue,那么我们就可以在 tests 文件夹下面建立一个名为 Notify.test.ts 的测试文件,然后写入如下测试代码:

(当然,由于你们没有我的 Notify.vue 组件,所以你们直接复制下面测试代码是会报错的,我在文末会放上开源链接,大家可以下载下来运行 pnpm test 查看效果。文章这里的话,大家只需要学 API 语法即可)

import { shallowMount } from "@vue/test-utils"
import { describe, expect, it } from "vitest"
import Notify from "@/components/Notify/index.vue"
import NotifyList from "@/components/Notify/NotifyList.vue"

describe("Notify", () => {
  it("正常渲染", () => {
    const wrapper = shallowMount(Notify)
    expect(wrapper.classes("notify")).toBe(true)
  })
})

describe("NotifyList", () => {
  it("List 长度为 0", () => {
    const wrapper = shallowMount(NotifyList, {
      props: {
        list: []
      }
    })
    expect(wrapper.find("el-empty").exists()).toBe(true)
  })
  it("List 长度不为 0", () => {
    const wrapper = shallowMount(NotifyList, {
      props: {
        list: [
          {
            title: ""
          }
        ]
      }
    })
    expect(wrapper.find("el-empty").exists()).toBe(false)
  })
})

Vitest API 解释

  • describe:形成一个作用域
  • test/it:定义了一组关于测试期望的方法,它接收测试名称和一个含有测试期望的函数
  • expect:创建断言
  • toBe:可用于断言基础对象是否相等,或者对象是否共享相同的引用
  • toEqual:断言检查值是否等于接收值,或者是同样的结构,如果是对象类型(将会使用递归的方法进行比较)

Vue Test Utils API 解释

  • shallowMount:创建一个包含被挂载和渲染的 Vue 组件的 Wrapper(shallowMount 只会渲染当前组件,而不会渲染它的子组件)
  • shallowMount 的第二个参数:可以传递 slots、props 等参数模拟真实情况
  • classes("notify"):如果有名为 notify 的类名,则返回 true,反之则返回 false
  • find:返回匹配选择器的第一个 DOM 节点或 Vue 组件的 Wrapper
  • exists:断言 Wrapper 或 WrapperArray 是否存在

开源代码

这个开源中后台管理系统模板就按照本文的方式集成好了 Vitest,并编写好了一些测试用例可供大家参考。

克隆下来并安装依赖后,运行 pnpm test,就可以体验集成好的 Vitest 了。