2022-12-14 | 使用指南 | UNLOCK | 更新时间:2022-12-19 14:36

Vitest的测试编辑及遇到的问题

安装

yarn add -D vitest || npm install -D vitest

配置命令

在项目中,需要配置后才可以使用

vite.config.js
// ... export default defineConfig({ test: { //... include: ['test/**/*.test.ts'], //匹配包含文件 // exclude:[], // 排除文件 environment: 'jsdom', //浏览器环境 }, })
package.json
{ "scripts": { "test": "vitest", } }
  • 可选 @vitest/coverage-c8 c8代码覆盖率测试

yarn add @vitest/coverage-c8 -D || npm install @vitest/coverage-c8 -D

package.json
{ "scripts": { // ... "coverage": "vitest run --coverage", } }
  • 可选 jsdom 测试浏览器环境

yarn add jsdom -D || npm install jsdom -D

vite.config.js
export default defineConfig({ //... test: { environment: 'jsdom' } })
  • 可选 @vitest/ui

可以添加 @vitest/ui vitest 的UI扩展库,可以直接在浏览器查看

yarn add @vitest/ui -D || npm install @vitest/ui -D

package.json
{ "scripts": { "vitestui": "启动vitest的UI界面", "vitestui": "vitest --ui" } }
  • 可选 ndb debugger

yarn add ndb gloable || npm install ndb -g

之后在想要的地方写 debugger ,在使用test进行测试就行

  • 可选 在代码里写测试
vite.config.js
import { defineConfig } from 'vitest/config' export default defineConfig({ test: { environment: 'node', includeSource: ['src/*.{js,ts}'] } })
  • 可选 使用@vue/test-utils对vue组件测试

yarn add –dev @vue/test-utils || npm install –save-dev @vue/test-utils

简单示例

import { mount } from '@vue/test-utils'
import TodoApp from './TodoApp.vue'

test('renders a todo', () => {
  const wrapper = mount(TodoApp) //包裹
  const todo = wrapper.get('[data-test="todo"]') //查找标签元素
  expect(todo.text()).toBe('Learn Vue.js 3') //断言文本
})

单元测试示例

在根目录添加 __tests__ 文件夹,添加测试文件

__tests__/index.test.ts
import { expect, test } from 'vitest' import { testName } from '../src/index' test('vitest-test', () => { expect(testName('jack')).toBe('jack') })
src/index.ts
export function testName (name) { return name }

简单介绍

test 别名it

test 定义了一组关于测试期望的方法。它接收测试名称(类似备注名称)和一个含有测试期望的函数,同时,可以提供一个超时时限(以毫秒为单位)用于指定等待多长时间后终止测试,默认为 5 秒

__test__/index.js
// 超时阈值(以毫秒为单位)作为第三个参数传递给测试。默认值为 5 秒 import { assert,test } from 'vitest' // 示例 test('name', async () => { /* ... */ }, 1000) // test.skip :跳过测试,没有错误 test.skip("skipped test", () => { assert.equal(Math.sqrt(4), 3); }); // test.skipIf :需要根据条件,跳过测试 const isDev = process.env.NODE_ENV === "development"; test.skipIf(isDev)("prod only test", () => { // 只要是开发环境就跳过 }); // test.runIf :需要根据条件,运行测试 test.runIf(isDev)("dev only test", () => { // 只在开发环境下进行测试 }); // test.only :只允许特点条件下运行 test.only("test", () => { // 仅运行此测试(以及仅标记有的其他测试) assert.equal(Math.sqrt(4), 2); }); // test.concurrent :并行运行测试 test.concurrent("concurrent test 1", async () => { }); test.concurrent("concurrent test 2", async () => { }); // test.skip、test.only 和 test.todo 适用于并发测试 test.skip.concurrent(/* ... */); // or test.concurrent.skip(/* ... */) test.only.concurrent(/* ... */); // or test.concurrent.only(/* ... */) test.todo.concurrent(/* ... */); // or test.concurrent.todo(/* ... */) // test.todo 存根测试 // 测试报告中将显示一个条目,不知道有什么用 test.todo("unimplemented test"); // test.fails //使用 test.fails 来指示测试断言将显式失败(不知道有什么屌用,没看到效果) const myAsyncFunc = () => new Promise((resolve) => resolve(1)); test.fails("failtest", async () => { await expect(myAsyncFunc()).rejects.toBe(1); }); // test.each 相同测试 // 当你需要使用不同的变量运行相同的测试时,请使用 test.each。 你可以按照测试参数的顺序,在测试名称插入符合printf 格式的参数 // %s:字符串; %d:数值; %i:整数; %f:小数; %j:json 格式; %o:对象; %#:对应的测试参数下标; %%:单个百分比符号 ('%') test.each([ [1, 1, 2], [1, 2, 3], [2, 1, 3], ])("name", (a, b, expected) => { expect(a + b).toBe(expected); });

expect 断言

expect 用来创建断言。在当前上下文中,可以使用 assertions 方法来断言一个语句。 Vitest 默认提供 chai 进行断言,同时基于 chai 实现兼容 Jest 的断言语句

__test__/index.js
import { expect } from "vitest"; const input = Math.sqrt(4); expect(input).toBe(2); //断言input的值是2 // not 否定断言 expect(input).not.toBe(2); //断言input的值不是2 // toBe 相同断言 (禁止使用浮点型) const stock = {type:"apples", count: 13} expect(stock.count).toBe(13); //断言stock.count等于13 // toBeCloseTo 相同断言 (浮点型) expect(0.2 + 0.1).toBeCloseTo(0.3, 5); //toBeCloseTo(结果,小数点后位数) // toBeDefined 断言有返回 expect( () => 3 ).toBeDefined(); //断言值不是是undefined,可以用来判断函数有返回值 // toBeUndefined 断言无返回 const an=()=>undefined expect( an() ).toBeUndefined(); //断言值是undefined,可以用来判断函数没有返回值 // toBeTruthy 断言为真 expect(0.2 + 0.1).toBeTruthy(); //将结果转为布尔值,结果为true // toBeFalsy 断言为假 expect(5-5).toBeFalsy() // toBeNull 断言为null expect(null).toBeNull() // toBeNaN 断言为NaN expect(NaN).toBeNull() // toBeTypeOf 断言类型(bigint, boolean, function, number, object, string, symbol, undefined) expect('actual').toBeTypeOf("string"); //断言类型为string // toBeInstanceOf 断言父类 const stocks = new Stocks(); test("stocks are instance of Stocks", () => { expect(stocks).toBeInstanceOf(Stocks); //断言你的父类是它(断言他是你爸) }); // toBeGreaterThan 断言大小 expect(5).toBeGreaterThan(1); //断言 5 大于 1 // toBeGreaterThanOrEqual 断言大小 expect(5).toBeGreaterThanOrEqual(1); //断言 5 大于等于 1 // toBeLessThan 断言大小 expect(1).toBeLessThan(5); //断言 1 小于 5 // toBeLessThanOrEqual 断言大小 expect(1).toBeLessThanOrEqual(5); //断言 1 小于等于 5 toEqual toStrictEqual toContain toContainEqual toHaveLength toHaveProperty toMatch toMatchObject toThrowError toMatchSnapshot toMatchInlineSnapshot toThrowErrorMatchingSnapshot toThrowErrorMatchingInlineSnapshot toHaveBeenCalled toHaveBeenCalledTimes toHaveBeenCalledWith toHaveBeenLastCalledWith toHaveBeenNthCalledWith toHaveReturned toHaveReturnedTimes toHaveReturnedWith toHaveLastReturnedWith toHaveNthReturnedWith toSatisfy resolves rejects // expect.assertions 断言异步调用几次 async function doAsync(...cbs) { await Promise.all(cbs.map((cb, index) => cb({ index }))); } test("all assertions are called", async () => { expect.assertions(2); // 本次异步调用了两次 function callback1(data) { expect(data).toBeTruthy(); //断言为真,函数有返回 } function callback2(data) { expect(data).toBeTruthy(); //断言为真,函数有返回 } await doAsync(callback1, callback2); }); // expect.hasAssertions 断言至少调用一次 function select(id) { return db.select({ id }).then((data) => { return Promise.all(cbs.map((cb) => cb(data))); }); } test("callback was called", async () => { expect.hasAssertions(); // 本次调用了 onSelect((data) => { expect(data).toBeTruthy(); }); await select(3); }); expect.anything expect.any expect.arrayContaining expect.objectContaining expect.stringContaining expect.stringMatching expect.addSnapshotSerializer expect.extend

bench 基准

bench 定义了一个基准。 在 Vitest 术语中,基准是定义一系列操作的函数。 Vitest 多次运行此函数以显示不同的性能结果

import { bench } from "vitest";

bench( // 报错: Error: `bench()` is only available in benchmark mode.
  "normal sorting",
  () => {
    const x = [1, 5, 4, 2, 3];
    x.sort((a, b) => {
      return a - b;
    });
  },
  { time: 1000 }
);

bench.skip
bench.only
bench.todo

describe 套件

当你在文件的顶层使用 test 或 bench 时,它们会被收集为它的隐式套件的一部分。 使用 describe 你可以在当前上下文中定义一个新套件,作为一组相关的测试或基准以及其他嵌套套件

import { test,describe } from 'vitest'
import { testName } from '../src/index'

const person = {
  isActive: true,
  age: 32,
};

describe("person", () => { //类似一个嵌套结构,仅用于展示效果
  test("person is defined", () => {
    expect(person).toBeDefin ed();
  });
})

// describe.skip 跳过
describe.skip("skipped suite", () => {
  test("sqrt", () => {
    // 跳过测试套件,不会有错误
    assert.equal(Math.sqrt(4), 3);
  });
});

// describe.only 只运行里面的,其他的不运行
describe.only("skipped suite", () => { //执行
  test("sqrt", () => {
    assert.equal(Math.sqrt(4), 3);
  });
});
test("sqrt", () => { //不执行
  assert.equal(Math.sqrt(4), 3);
});

describe.concurrent
describe.shuffle
describe.todo
describe.each

Vi 工具函数

// vi.advanceTimersByTime 定时停止
let i = 0;
setInterval(() => console.log(++i), 50);
vi.advanceTimersByTime(150); // 150 毫秒后停止执行

vi.advanceTimersToNextTimer
vi.clearAllMocks
vi.clearAllTimers
vi.dynamicImportSettled
vi.fn
vi.getMockedSystemTime
vi.getRealSystemTime
vi.mock
vi.mocked
vi.importActual
vi.importMock
vi.resetAllMocks
vi.resetConfig
vi.resetModules
vi.restoreAllMocks
vi.restoreCurrentDate
vi.runAllTicks
vi.runAllTimers
vi.runOnlyPendingTimers
vi.setSystemTime
vi.setConfig
vi.spyOn
vi.stubGlobal
vi.unmock
vi.useFakeTimers
vi.useRealTimers

MockInstance Methods

getMockName
mockClear
mockName
mockImplementation
mockImplementationOnce
mockRejectedValue
mockRejectedValueOnce
mockReset
mockRestore
mockResolvedValue
mockResolvedValueOnce
mockReturnThis
mockReturnValue
mockReturnValueOnce

MockInstance Properties

mock.calls
mock.lastCall
mock.results
mock.instances

问题集合

执行vitestui 报错 Cannot read properties of undefined (reading ‘config’)

vitest 和 vitest/ui 的版本和 vite 不匹配

pnpm i vitest@latest @vitest/ui@latest -D