vitest单元测试配合@vue/test-utils之组件单元测试篇

what is vitest & test-utils

vitest 是由 vite 提供支持的极速单元测试框架,VueTestUtils 是 Vue.js 的官方测试实用程序库,vitest 本身是不支持单元组件测试的,需要配合 test-utils 来完成组件单元测试,安装与基本 API 就不再赘述,学会阅读文档与查找资料是一个程序员的基本功

demo

/* Component */
<template>
  <div>
    <div class="test-utils-value">值为:{{ num }}</div>
    <button class="test-utils-button" @click="increment">测试按钮</button>
  </div>
</template>

<script setup lang="ts">
  import { ref } from 'vue'
  import type { Ref } from 'vue'
  const num: Ref<number> = ref(1)
  function increment() {
    num.value++
  }
</script>
// spec | test
import { describe, it, expect } from 'vitest'
import { shallowMount } from '@vue/test-utils'
import AddNum from '@/views/AddNum.vue'

describe('组件单元测试', () => {
  it('test1', async () => {
    const wrapper = shallowMount(AddNum)
    const btn = '.test-utils-button'
    const value = '.test-utils-value'
    expect(wrapper.find(value).text()).toContain('值为:1')
    await wrapper.find(btn).trigger('click')
    expect(wrapper.find(value).text()).toBe('值为:2')
  })
})
  1. demo 由一个组件和测试文件组成
  2. 组件的逻辑非常简单,按下按钮则数字+1,页面显示实时数字
  3. 测试代码中使用 test-utils 库的 shallowMount 方法浅渲染挂载组件(*:浅渲染只渲染当前组件,不会渲染它的子组件,从而避免在测试中与子组件的行为产生干扰)
  • 组件通过 find 方法返回查找元素,再通过 text 方法返回元素的文本内容
  • 然后使用 vitest 库的 expect 创建断言,toContain 是断言检查值是否在数组中,toBe 是断言基础对象是否相等
  • trigger 是 test-utils 中触发 DOM 事件的方法,demo 中触发了点击事件,模拟用户按下了按钮的操作,按下按钮前后都断言了,会判断实际执行结果与预期结果是否一致,如果不一致则会抛出错误
  • 如将tobe('值为:2')改为tobe('值为:3'),就会提示哪一个测试文件中的哪一个测试用例失败,并展示错误的预期值和实际的执行结果
- Expected   "值为:3"
+ Received   "值为:2"

tips

虽然这是一个非常简单 demo,但它还是有很多值得注意的知识点的

  • describe 可以在文件顶层直接使用testbench,它们会被收集为隐式套件的一部分,也可以用describe在当前上下文定义一个新套件,作为一组相关的测试或嵌套套件
  • it ittest的别名,使用ittest都是可以的
  • shallowMount 按照文档描述它是使用挂载组件的别名,所以也可以使用mount(Component, { shallow: true })来浅渲染挂载组件,shallow 的默认值是 false
  • async/await 可以看到 trigger 前使用了 await,这与我们寻常使用 async/await 有一点细微的差别,假如我们去掉 async/await,测试用例将会失败,因为按钮虽然按下了,值也自增了,但 vue 不会立即更新 DOM,而是等到下一个事件循环勾选之后再更新,所以断言会在在 vue 更新之前被调用,拿到的实际执行结果还是初始值 1,与预期值 2 不符,然后抛出错误,这感觉是不是很熟悉,这不就像 Vue 的异步更新策略导致我们对数据的修改不会立马体现到页面变化上,此时如果想要立即获取更新后的 dom 的状态,我们就需要使用到…对,没错就是我们的老朋友nexttick()
import { nextTick } from 'vue'

it('test1', async () => {
  const wrapper = shallowMount(AddNum)
  const btn = '.test-utils-button'
  const value = '.test-utils-value'
  expect(wrapper.find(value).text()).toContain('值为:1')
  wrapper.find(btn).trigger('click')
  await nexttick()
  expect(wrapper.find(value).text()).toBe('值为:2')
})

因为这是很常见的一个问题,test-utils提供了一个快捷方式,可以直接在await后跟触发DOM的事件,省略掉nexttick(),即await wrapper.find(btn).trigger('click'),如此一来我们断言的实际结果就是自增过后的数字,与预期结果相符,测试用例通过

原文链接:https://juejin.cn/post/7212603829572206647 作者:Selicens

(0)
上一篇 2023年3月21日 下午4:16
下一篇 2023年3月21日 下午4:26

相关推荐

发表回复

登录后才能评论