编写易于测试的 Vue 3 组件

708 篇文章 24 订阅
646 篇文章 0 订阅

Vue Test Utils 2.x(VTU)帮助你为 Vue 3 组件编写测试。然而,VTU 的功能也有限,比如我们无法使用包裹器方法 setData 来修改 <script setup> 中的响应式数据。以下是一些建议,帮助你编写易于测试的代码,并编写有意义且易于维护的测试。

以下列表提供了一般指导,对于常见情况可能会有所帮助。

不要测试实现细节

从用户的角度来看,以输入和输出为思考方式。大致上,这是你在为 Vue 组件编写测试时应考虑的所有内容:

输入示例
交互点击、输入等任何“人类”交互
Props组件接收的参数
数据流来自 API 调用、数据订阅等的数据流
输出示例
DOM 元素渲染到文档中的任何可观察节点
事件通过 $emit 触发的事件
副作用例如 console.log 或 API 调用

其他所有内容都是实现细节

请注意,此列表不包括诸如内部方法、中间状态甚至数据等元素。

经验法则是测试不应在重构时失败,也就是说,当我们在不改变行为的情况下更改其内部实现时,测试不应该失败。如果发生这种情况,则测试可能依赖于实现细节。

例如,假设有一个基本的计数器组件,其中包含一个按钮来递增计数器:

<script lang="ts">
  export default {
    data() {
      return { count: 0 }
    },
    methods: {
      increment() {
        this.count++
      }
    }
  }
</script>

<template>
  <p class="paragraph">Times clicked: {{ count }}</p>
  <button @click="increment">increment</button>
</template>

我们可以编写以下测试:

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

test('counter text updates', async () => {
  const wrapper = mount(Counter)
  const paragraph = wrapper.find('.paragraph')
  expect(paragraph.text()).toBe('Times clicked: 0')
  await wrapper.setData({ count: 2 })
  expect(paragraph.text()).toBe('Times clicked: 2')
})

请注意,这里我们更新了其内部数据,并且我们还依赖于细节(从用户的角度来看),例如 CSS 类名。

请注意,更改数据或 CSS 类名都会导致测试失败。但组件仍将按预期工作。这被称为误报(false positive)

相反,下面的测试试图坚持使用上面列出的输入和输出:

// Counter.test.ts

test('text updates on clicking by VTU', async () => {
  const wrapper = mount(Counter)
  expect(wrapper.text()).toContain('Times clicked: 0')
  const button = wrapper.find('button')
  await button.trigger('click')
  await button.trigger('click')
  expect(wrapper.text()).toContain('Times clicked: 2')
})

诸如vue Testing Library(VTL)之类的库是基于这些原则构建的。VTL 遵从测试应该更接近用户与应用程序的实际交互,而不仅仅关注内部实现细节。它鼓励开发人员编写与用户行为相对应的测试代码,从而增加测试的可读性和可维护性。

// Counter.test.ts
import { fireEvent, render } from '@testing-library/vue'
import '@testing-library/jest-dom'

test('text updates on clicking by VTL', async () => {
  const { getByText, getByRole } = render(Counter)
  const text = getByText('Times clicked: 0')
  expect(text).toBeInTheDocument()
  const button = getByRole('button', { name: /increment/i })
  await fireEvent.click(button)
  await fireEvent.click(button)
  expect(text).toHaveTextContent('Times clicked: 2')
})

和 VUT 编写的组件测试二相比,VTL 编写的组件测试三更语义化,而且更通用。VTL 为包括 React、Angular 和 Vue 等框架封装 API,更适合测试多框架的 UI 组件库。因此强烈推荐尽量使用 VTL 组件测试,不得不处理组件实例时才使用 VUT 。

你的测试越像你的软件的使用方式,你就会更有信心。

尽量不要使用 setData

VTU 2.x 主要目标是测试 Vue 3 组件,目前该工具库对选项式 API 支持要比组合式 API 好,比如包裹器方法 setData 或挂载选项 data 不会修改组合式 API 的 setup() 数据。

将之前的 Counter.vue 替换成下面的 <script setup> 语法:

<script lang="ts" setup>
  import { ref } from 'vue'
  const count = ref(0)
  const increment = () => {
    count.value++
  }
</script>

<template>
  <p class="paragraph">Times clicked: {{ count }}</p>
  <button @click="increment">increment</button>
</template>

如你所见,测试一会失败。后面两个测试仍会成功,可见编写测试的组件是遵从最佳实践是很重要的。

FAIL src/vtu/easy/TheCounter.test.ts > counter text updates TypeError: Cannot add property count, object is not extensible ❯ node_modules/@vue/test-utils/dist/vue-test-utils.esm-bundler.mjs:219:25

注意:目前,我们可以通过包裹器当前组件的 setupState 属性来修改 <script setup> 中的响应式数据:

test('counter text updates', async () => {
  const wrapper = mount(Counter)
  const paragraph = wrapper.find('.paragraph')
  expect(paragraph.text()).toBe('Times clicked: 0')
  wrapper.getCurrentComponent().setupState.count = 2
  await wrapper.vm.$nextTick()
  expect(paragraph.text()).toBe('Times clicked: 2')
})

这个属性藏得很深😁,以后有可能被官方取消,慎用。

构建更小、更简单的组件

一个经验法则是,如果组件功能较少,则更容易进行测试。

将组件分解为较小的组件将使它们更易于组合和理解。以下是一些建议,可以使组件更简单。

提取 API 调用

通常,你将在整个应用程序中执行多个 HTTP 请求。从测试的角度来看,HTTP 请求为组件提供了输入,组件也可以发送 HTTP 请求。

如果对测试 API 调用不熟悉,请查看进行HTP请求指南。

提取复杂的方法

有时,组件可能包含复杂的方法、执行繁重的计算或使用多个依赖项。

这里的建议是将此方法提取出来并导入到组件中。这样,你可以使用 Jest 或任何其他测试运行器单独测试该方法。

这样做的另一个好处是,组件更容易理解,因为复杂逻辑被封装在另一个文件中。

此外,如果复杂的方法难以设置或速度较慢,你可能希望模拟它以使测试更简单和更快。进行HTTP请求的示例是一个很好的例子-axios 是一个相当复杂的库!

在编写组件之前编写测试

如果在编写代码之前编写测试,就不可能编写无法测试的代码!

入门指南提供了一个示例,说明在编写代码之前编写测试如何导致可测试的组件。它还可以帮助你检测和测试边缘情况。

最后:下方这份完整的软件测试视频教程已经整理上传完成,需要的朋友们可以自行领取【保证100%免费】

在这里插入图片描述

软件测试面试文档

我们学习必然是为了找到高薪的工作,下面这些面试题是来自阿里、腾讯、字节等一线互联网大厂最新的面试资料,并且有字节大佬给出了权威的解答,刷完这一套面试资料相信大家都能找到满意的工作。

图片

整套资料获取

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值