模拟组合式函数、存储与 API
vi.mock()、模拟 useFetch、模拟 Pinia 存储,以及在测试中模拟路由器
模拟组合式函数、存储与 API 是 CoddyKit 上的免费 Vue Academy 课时。 这是第 4 节课,共 4 节。 你可以在下方免费阅读本课时的完整内容 — 然后在浏览器中使用内置代码编辑器和全天候 AI 导师进行实践。 这是 Vue Academy 学习路径的一部分,你的进度在网页和 CoddyKit 应用中同步。 Vue Academy 课程共包含 4 节课。
为何使用 mock?
单元测试应当隔离正在测试的组件。真实的网络请求、真实的存储库和复杂的组合式函数会让测试变慢且不稳定。模拟会用可控的伪对象替换这些依赖项。
vi.fn:模拟函数
vi.fn()会创建一个可跟踪的函数。您可以检查它的调用方式,并控制它返回的内容。它是所有模拟操作的基础构件。
import { vi } from "vitest"
const onSave = vi.fn()
onSave("draft")
expect(onSave).toHaveBeenCalledWith("draft")
expect(onSave).toHaveBeenCalledTimes(1)设置返回值
对于同步代码,可以使用mockReturnValue;对于异步代码,可以使用mockResolvedValue(返回一个已解决的 promise),从而控制模拟对象的输出。
const getId = vi.fn().mockReturnValue(42)
expect(getId()).toBe(42)
const fetchUser = vi.fn().mockResolvedValue({ name: "Ada" })
// await fetchUser() => { name: "Ada" }模拟组合式函数模块
vi.mock(path)会替换整个模块。请提供一个返回伪导出的工厂函数。您可以用它替换组合式函数,这样组件就能获得可预测的数据。
import { vi } from "vitest"
vi.mock("@/composables/useUser", () => ({
useUser: () => ({
user: { value: { name: "Ada" } },
isLoading: { value: false },
}),
}))vi.mock 提升
vi.mock调用会被提升到文件顶部,在导入执行前运行。因此,工厂函数不能引用之后才定义的外部变量——请在工厂函数内部或通过vi.hoisted声明所需的辅助项。
// This runs before imports regardless of position.
vi.mock("@/api", () => ({ getPosts: vi.fn() }))
import { getPosts } from "@/api" // already the mock测试 Pinia 存储库
使用 Pinia 存储库的组件需要在测试中提供一个存储库。@pinia/testing提供了createTestingPinia,它会为您创建一个操作默认被模拟的存储库。
// terminal: npm install -D @pinia/testing
import { createTestingPinia } from "@pinia/testing"安装测试 Pinia
挂载组件时,请通过全局plugins选项传入测试 Pinia。您还可以预先设置初始状态。
import { mount } from "@vue/test-utils"
import { createTestingPinia } from "@pinia/testing"
const wrapper = mount(Profile, {
global: {
plugins: [createTestingPinia({
initialState: { user: { name: "Ada" } },
})],
},
})断言存储库操作
默认情况下,操作会被替换为空实现(不会运行),因此您可以断言它们是否被分发。获取存储库并检查间谍函数。
import { useUserStore } from "@/stores/user"
const store = useUserStore()
await wrapper.get("button.logout").trigger("click")
expect(store.logout).toHaveBeenCalled()监视网络请求
您不必替换整个模块,也可以监视全局对象。vi.spyOn(global, "fetch")会包装真实的 fetch,这样您就可以覆盖并检查它。
const spy = vi.spyOn(global, "fetch").mockResolvedValue({
ok: true,
json: async () => ({ items: [1, 2, 3] }),
})完整的网络请求测试
模拟 fetch,触发操作,刷新 promise,然后断言渲染出的数据,以及 fetch 是否使用正确的 URL 被调用。
it("loads items", async () => {
vi.spyOn(global, "fetch").mockResolvedValue({
ok: true,
json: async () => ({ items: ["a", "b"] }),
})
const wrapper = mount(List)
await flushPromises()
expect(global.fetch).toHaveBeenCalledWith("/api/items")
expect(wrapper.findAll("li")).toHaveLength(2)
})在测试之间重置模拟对象
共享的模拟对象会累积调用历史。请在beforeEach中重置它们(或者在配置中启用clearMocks),这样一个测试就不会影响另一个测试。
import { beforeEach, vi } from "vitest"
beforeEach(() => {
vi.clearAllMocks()
})快速检查
检查您对模拟的理解。
总结
您学会了如何在测试中模拟依赖项:
vi.fn()会创建可跟踪的函数;使用mockReturnValue/mockResolvedValue控制输出。vi.mock(path, factory)会替换模块(例如组合式函数);它会被提升到导入语句之前。@pinia/testing中的createTestingPinia会提供一个操作被替换为空实现的存储库,您可以对这些操作进行断言。vi.spyOn(global, "fetch").mockResolvedValue(...)可以伪造网络请求。- 使用
vi.clearAllMocks()在测试之间重置模拟对象。
常见问题解答
「模拟组合式函数、存储与 API」课时是免费的吗?
是的 — 「模拟组合式函数、存储与 API」的完整文本可在网页上免费阅读。要进行交互式练习(内置代码编辑器和全天候 AI 导师)并解锁 Vue Academy 课程的其余内容,请升级到 CoddyKit PRO。 Vue Academy 课程共包含 4 节课。
「模拟组合式函数、存储与 API」这节课中我会学到什么?
vi.mock()、模拟 useFetch、模拟 Pinia 存储,以及在测试中模拟路由器 你通过在浏览器中直接运行的动手代码来练习 Vue Academy,全天候 AI 导师会在你学习这节课的过程中回答你的问题。
学习 Vue Academy 需要有经验吗?
无需任何先前经验。CoddyKit 上的 Vue Academy 课程适合初学者到高级学习者,你可以从这里开始或从头开始,按照自己的节奏学习。 这是第 4 节课,共 4 节。
「模拟组合式函数、存储与 API」课时需要多长时间?
大多数 CoddyKit 课程大约需要 5–10 分钟。每节课都很精短且互动,所以你能稳步进步,并在网页和应用中从离开的地方继续。
我能在这节 Vue Academy 课中编写并运行代码吗?
能。每节 Vue Academy 课都包含内置代码编辑器,你可以在浏览器中直接编写并运行真实代码,并获得即时 AI 反馈 — 无需本地设置。
此课程中的所有课时
- 为 Vue 项目配置 Vitest
- 挂载与查询组件
- 测试用户交互与事件
- 模拟组合式函数、存储与 API