Skip to content

发现的问题

  • 新建一堆不同属性的组件,肉眼观测
  • 更新代码,要再次进行手动测试

测试在国内被严重忽视

  • 没有时间
  • 需求一直更改
  • 不知道怎样写测试

测试的优点

  • 自动化完成流程,保证代码的运行结果
  • 更早发现Bug
  • 重构和升级更加容易和可靠

测试金字塔

image-20250615104442941

Unit Test:单元测试,把代码拆分成独立的部分,它们之间没有相互的依赖

Service Test:把Unit Test结合起来

UI Test:也称为e2e Test,模拟真实的用户场景,对整个应用进行测试

image-20250615104753914

上面这个图被称为“冰淇淋图”,在国内是大部分是靠QA和开发手动测试

组件化的框架(React、Vue)非常适合写单元测试

  • 组件化,独立单元,互不影响
  • 属性和界面的映射,固定输入,固定输出
  • 单向数据流
  • 状态管理工具的stroe可以单独写测试

需要选取两种测试工具

  • 通用的测试框架
  • 针对对应库(React或者Vue)的测试库

通用测试框架

  • Mocha
  • Jest
  • Vitest

Vitest的优点

文档地址:https://cn.vitest.dev/guide/why.html

测试框架的几大功能

安装Vitest

json
# Vitest 需要 Vite >=v5.0.0 和 Node >=v18.0.0
npm install -D vitest

断言的写法

example.test.ts

typescript
import { test, describe, vi, expect, Mocked } from "vitest";
import { testFn, request } from "./utils";
import axios from "axios";
vi.mock("axios");
const mockedAxios = axios as Mocked<typeof axios>; // 解决ts报错
// callback test
// mock
describe("functions", () => {
  test("create a mock function", () => {
    const callback = vi.fn();
    testFn(12, callback);
    expect(callback).toHaveBeenCalled(); // 监控callback是否被调用
    expect(callback).toHaveBeenCalledWith(12); //监控callback的传参
  });
  test("spy on method", () => {
    const obj = {
      getName: () => 1,
    };
    const spy = vi.spyOn(obj, "getName"); // 使用spyOn可以让obj和getName产生联系
    obj.getName();
    expect(spy).toHaveBeenCalled(); // 监控getName是被调用
    obj.getName();
    expect(spy).toHaveBeenCalledTimes(2); // 监控getName被调用的次数
  });
  test("mock third party module", async () => {
    // mockedAxios.get.mockImplementation(() => Promise.resolve({ data: 123 }))
    mockedAxios.get.mockResolvedValue({ data: 123 }); // 上面的简写
    const result = await request();
    expect(result).toBe(123);
  });
});

utils.ts

typescript
import axios from 'axios'

export function testFn(number: number, callback: Function) {
  if (number > 10 ) {
    callback(number)
  }
}

export async function request() {
  const { data } = await axios.get('fake.url')
  return data
}

查看结果

json
npx vitest example
image-20250615123319668

基于Vue的测试工具

Vitest的配置文件

https://cn.vitest.dev/config/

Stub子组件

https://test-utils.vuejs.org/zh/guide/advanced/stubs-shallow-mount.html

具体看Button组件的Button.test.ts

Vitest.config.ts

如果想要重载Vite.config.ts的配置,可以单独创建一个vitest.config.ts

typescript
/// <reference types="vitest" />

import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
import vueJsx from '@vitejs/plugin-vue-jsx'
import VueMacros from 'unplugin-vue-macros'

// https://vitejs.dev/config/
export default defineConfig({
  plugins: [
    VueMacros.vite({
      plugins: {
        vue: vue(),
        vueJsx: vueJsx(),
      },
    })
  ],
  // 使用了<reference types="vitest" />这里test才会有类型提示
  test: {
    globals: true,
    environment: 'jsdom'
  }
})