大家好,这里是大家的林语冰。本期《前端翻译计划》共享的是 Vue 周报推荐的一篇关于测试 Vue 组合式函数的博客。
免责声明
本文属于是语冰的直男翻译了属于是,略有删改,仅供粉丝参考,英文原味版请临幸 How to Test Vue Composables。
引言
在本文中,我想辅助您更好地理解如何在 Vue 中测试组合式函数。如今,我们的大部分业务逻辑或 UI 逻辑通常封装在组合式函数中,这就是我认为了解如何测试它们十分重要重要的原因。
定义
在深入探讨主题之前,了解若干有关测试的基本概念十分重要。这些基础知识将有助于阐明测试 Vue 组合式函数在更广泛的软件测试领域中的位置。
组合式函数
Vue 组合式函数是可复用的组合函数,用于封装和管理响应式状态和逻辑。它们允许以灵活的方式跨组件组织和重用代码,增强模块化和可维护性。
测试金字塔
测试金字塔是一个概念性的隐喻,它说明了不同类型测试的理想平衡。它建议使用一大坨单元测试,辅以一小坨集成测试集,并添加更小坨端到端测试集。这种结构确保了高效的测试覆盖率。
单元测试以及测试组合式函数如何成为单元测试
单元测试是指单独测试单个代码单元的做法。在 Vue 的上下文中,测试组合式函数是单元测试的一种形式。它涉及严格验证这些隔离的、可复用代码块的功能,确保它们在没有外部依赖的情况下正常运行。
测试组合式函数
Vue 组合式函数本质上是函数,利用了 Vue 的响应式系统。鉴于这种独特的性质,我们可以将组合式函数分类为不同的类型。一方面,由于自治组合式函数(Independent Composables
)的隔离性,可以直接测试它们。另一方面,我们有依赖组合式函数(Dependent COmposables
),它们只有集成到组件中才能奏效。接下来我将深入探讨这些不同的类型,为每种类型提供示例,并指导您为这两种类型制定有效的测试策略。
自治组合式函数
自治组合式函数门使用 Vue 的响应式 API。这些可组合项独立于 Vue 组件实例运行,因此易于测试。
示例和测试策略:
下面是一个自治组合式函数的示例,它计算两个响应值的总和:
ts
useSum(a: Ref<number>, b: Ref<number>): ComputedRef<number> {
return computed(() => a.value + b.value)
}
要测试这个组合式函数,您可以直接调用它并断言其返回状态:
js
describe('useSum', () => {
it('correctly computes the sum of two numbers', () => {
const num1 = ref(2)
const num2 = ref(3)
const sum = useSum(num1, num2)
expect(sum.value).toBe(5)
})
})
此测试通过传递响应式引用并断言计算结果来直接检查 useSum 的功能。
依赖组合式函数
依赖组合式函数的差异在于它们依赖于 Vue 的组件实例。它们通常利用生命周期钩子或上下文等功能进行操作。这些组合式函数是组件的组成部分,需要一种独特的测试方法,因为不同于自治可组合项。
示例和用法:
一个示例性的依赖组合式函数是 useLocalStorage
。这个组合式函数有助于与浏览器的 localStorage 进行交互,并利用 onMounted
生命周期钩子初始化:
ts
function useLocalStorage<T>(key: string, initialValue: T) {
const value = ref(initialValue)
function loadFromLocalStorage() {
const storedValue = localStorage.getItem(key)
if (storedValue !== null) {
value.value = JSON.parse(storedValue)
}
}
onMounted(loadFromLocalStorage)
watch(value, newValue => {
localStorage.setItem(key, JSON.stringify(newValue))
})
return { value }
}
export default useLocalStorage
举个栗子,可以在组件中使用该组合式函数来创建持久计数器:
这里的主要好处是响应式 count
属性与 localStorage
的无缝同步,确保跨会话的持久性。
测试策略
为了有效地测试 useLocalStorage
,尤其是考虑到 onMounted
生命周期,我们开始面临挑战。让我们从基本的测试设置开始:
js
describe('useLocalStorage', () => {
it('should load the initialValue', () => {
const { value } = useLocalStorage('testKey', 'initValue')
expect(value.value).toBe('initValue')
})
it('should load from localStorage', async () => {
localStorage.setItem('testKey', JSON.stringify('fromStorage'))
const { value } = useLocalStorage('testKey', 'initialValue')
expect(value.value).toBe('fromStorage')
})
})
在这里,首个测试将通过,断言组合式函数初始化为给定的 initialValue
。但是,第二个测试期望从 localStorage 加载预先存在的值会失败。之所以出现挑战,是因为 onMounted
在测试期间没有触发生命周期钩子。为了搞定此问题,我们需要重构我们的组合式函数或测试设置,模拟组件安装过程。
使用 withSetup
辅助函数增强测试
为了便于测试依赖 Vue 生命周期钩子的组合式函数,我们开发了一个 withSetup
高阶函数。此工具允许我们编程创建一个 Vue 组件上下文,主要聚焦组合式函数通常使用的 setup
生命周期函数。
withSetup
简介:
withSetup
旨在模拟 Vue 组件的 setup
函数,使我们能够在密切模仿其实际使用的环境中测试组合式函数。该函数接受一个组合式函数,并返回组合式函数的结果和一个 Vue App 实例。此 setup
允许综合测试,包括生命周期和响应性功能。
ts
import type { App } from 'vue'
import { createApp } from 'vue'
export function withSetup<T>(composable: () => T): [T, App] {
let result: T
const app = createApp({
setup() {
result = composable()
return () => {}
}
})
app.mount(document.createElement('div'))
return [result, app]
}
在此实现中,withSetup
挂载在一个最小的 Vue App,并在 setup
阶段执行提供的组合式函数。这种方法允许我们捕获组合式函数的输出并将其与 App 实例一起返回,以便进一步测试。
在测试中使用 withSetup
:
借助 withSetup
,我们可以增强组合式函数的测试策略,比如 useLocalStorage
,确保它们即使在依赖生命周期钩子时也能如期运行:
js
it('should load the value from localStorage if it was set before', async () => {
localStorage.setItem('testKey', JSON.stringify('valueFromLocalStorage'))
const [result] = withSetup(() => useLocalStorage('testKey', 'testValue'))
expect(result.value.value).toBe('valueFromLocalStorage')
})
这个测试演示了 withSetup
如何让组合式函数像常规 Vue 组件的一部分一样执行,确保 onMounted
生命周期钩子如期触发。此外,强大的 TypeScript 支持通过提供清晰的类型推断和错误检查来增强开发体验。
完结撒花
在测试 Vue 组合式函数的探索中,我们发现了两个不同的类别:自治组合式函数和依赖组合式函数。自治组合式函数是独立的,可以像常规函数一样进行测试,展示了简单的测试程序。同时,依赖组合式函数与 Vue 的组件系统和生命周期钩子纠缠不清,需要一种更细致的方法。对于这些,我们学习了利用辅助函数(比如 withSetup
)来模拟组件上下文的有效性,从而实现综合测试。
您现在收看的是前端翻译计划,学废了的小伙伴可以订阅此专栏合集,我们每天佛系投稿,欢迎持续关注前端生态。谢谢大家的点赞,掰掰~