前端单元测试

前言

为什么要做单元测试

  1. 需求变更频繁
    需求中永远不变的是: 需求永远在变.

  2. 需求不一定完善
    产品关心的是: 需求的重点业务.
    比如说想要建个农场养鸡, 产品只要求能按质按量正常生产小鸡, 小鸡的存活养大概率满足预期(80%)即可, 至于农场是建在草原,沙漠,还是火山; 农场发生火灾, 发生瘟疫怎么应对, 怎么预防, 他们可能不会去关注

  3. 提测质量不高,bug多
    提测后的1-3天, BUG井喷式出现;
    测试同学抱怨, 改完bug A,以前修复的bug B又复现了; 或者说出现了新的bug C

我们有很多方法可以给自己安全感,比如:

  1. 配置代码检测工具 ESLint
  2. 安装拼写检查插件 Code Spell Checker
  3. 代码评审 Code Review
  4. 结对编程 Pair programming
  5. 编写单元测试 Unit Test

本文主要给大家介绍如何在 Vue 项目中编写单元测试。

搭建

我们的单元测试环境基于 vitest + @vue/test-utils。
前提:你需要有一个 Vue 项目,没有的话可以参考 Vite 官网进行创建。
第一步,在你的 Vue 项目中安装必要的依赖包。

npm i -D vitest @vue/test-utils happy-dom @vitest/coverage-v8

在 vite.config.ts 文件中增加以下配置。

import { defineConfig } from 'vitest/config'
import vue from '@vitejs/plugin-vue'

export default defineConfig({
  plugins: [vue()],

  // 新增
  test: {
    environment: 'happy-dom'
  }
})

在 package.json 文件中增加相应的脚本命令


  "scripts": {
    "dev": "vite",
    "build": "vue-tsc && vite build",
    "preview": "vite preview",
    
    // 新增
    "test": "vitest"
  },

我们尝试执行以下命令:

npm test	

会发现控制台会打印以下日志:

$ npm test

> vue3-vite@0.0.0 test
> vitest


 DEV  v0.33.0 /vue3-vite-demo

include: **/*.{test,spec}.?(c|m)[jt]s?(x)
exclude:  **/node_modules/**, **/dist/**, **/cypress/**, **/.{idea,git,cache,output,temp}/**, **/{karma,rollup,webpack,vite,vitest,jest,ava,babel,nyc,cypress,tsup,build}.config.*
watch exclude:  **/node_modules/**, **/dist/**

No test files found, exiting with code 1

意思是:没有找到单元测试文件。

除此之外,我们还能获取一些额外的信息,比如 include 表明了单元测试文件的命令格式:

**/*.{test,spec}.?(c|m)[jt]s?(x)

我们在 src/components 目录下创建一个 HelloWorld.spec.ts 文件。

import { mount } from '@vue/test-utils'
import { describe, it, expect } from 'vitest'
import HelloWorld from './HelloWorld.vue'

describe('测试 HelloWorld 组件', () => {

  it('测试基本功能', async () => {
    const wrapper = mount(HelloWorld)
    expect(wrapper.exists()).toBeTruthy()
  })
})

再次执行 npm test 命令

$ npm test

 ✓ src/components/HelloWorld.spec.ts (1)
   ✓ 测试 HelloWorld 组件 (1)
     ✓ 测试基本功能

 Test Files  1 passed (1)
      Tests  1 passed (1)
   Start at  23:34:49
   Duration  126ms

单测完善程度的衡量

单测完善程度的衡量用覆盖率来衡量

关于测试覆盖率,我们大致了解下以下几个常见的计算维度:

  • 行覆盖率:可执行语句执行的比例
  • 函数覆盖率:函数被调用的比例
  • 分支覆盖率:判断语句分支被执行的比例

来看下面这个例子:

覆盖率
对于测试用例 foo(4),分支覆盖率只有50%,原因是 foo(4) 只测试了if 为 true 的情况,没有测试到 if 为 false 的情况。

如果想要分支覆盖率达到100%,还应该测试 foo(5)。

单测三大件:describe / test / expect

一个单元测试包含三个部分:

  • describe 测试套,里面可以包含多个测试用例,
  • it(test) 测试用例
  • expect 断言语句
import { describe, it, expect } from 'vitest'

describe('测试 HelloWorld 组件', () => {
  it('测试基本功能', async () => {
    const wrapper = mount(HelloWorld)
    wrapper.
    expect(wrapper.exists()).toBeTruthy()
    expect(wrapper.find('.card').exists()).toBeTruthy()
  })
  
  it('测试 msg 属性', () => { ... })
})

写单测就是写断言

有了 wrapper,就可以对 Vue 组件做断言。

比如以下断言用于判断 DOM 节点 .card 是否存在,toBeTruthy()用于断言一个值是否为 true。

expect(wrapper.find('.card').exists()).toBeTruthy()

常见的断言类型有:

  • toBe:用于断言原始类型是否相等,比如:expect(1+1).toBe(2)
  • toBeTruthy:用于断言一个值是否为 true
  • not:用于否定断言,比如:expect(1+1).toBe(3)
  • toBeGreaterThan:断言实际值是否大于接收到的值
  • toEqual:断言实际值是否等于接收到的值或具有相同的结构(如果是对象,则递归比较它们),注意和 toBe 的区别
  • toContain:断言实际值是否在数组中
  • toMatch:断言字符串是否与正则表达式或字符串匹配
  • toHaveBeenCalled:用于测试函数是否已被调用

更多断言类型请参考:Vitest 官网

  • 27
    点赞
  • 21
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值