You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Vitest测试Pinia状态未更新求助:API调用后projects数组为空

问题:Pinia Store中getAllProjects方法测试时状态未更新

开发Vue.js应用时,使用Pinia做状态管理、Vitest做单元测试。Pinia store里的getAllProjects方法通过API获取项目数据并更新store状态,但测试时模拟API调用后,store的projects数组未按预期更新,测试失败提示:

Expected: 3, Received: 0

原因分析

  • 未模拟axios请求:当前测试代码没有对axios的get请求做模拟,测试时会发送真实API请求,而真实请求无返回数据,导致projects数组保持为空。
  • state缺失loading字段:store的state未定义loading属性,但在getAllProjects中直接赋值this.loading = true,会导致状态异常,可能影响后续逻辑执行。
  • async/await与.then/.catch混用:在async函数里同时使用两种异步写法,逻辑嵌套混乱,可能导致状态更新时机出现问题。

解决方案

步骤1:修复Pinia Store代码

在state中添加loading字段,同时重构getAllProjects方法,统一使用async/await写法:

import { defineStore } from 'pinia';
import axios from '@/utils/axios';
import Swal from 'sweetalert2';

export const useProjectStore = defineStore('project', {
    state: () => ({
        projects: [],
        loading: false // 新增loading字段
    }),
    actions: {
        async getAllProjects() {
            this.loading = true;

            try {
                const response = await axios.get('projects', {
                    timeout: 15000
                });
                this.projects = response.data;
            } catch (error) {
                console.error(error);
            } finally {
                this.loading = false; // 用finally确保loading一定会被重置
            }
        },
    },
    persist: true,
});

步骤2:修改Vitest测试代码,模拟axios请求

使用Vitest的vi.mock模拟axios模块,让get方法返回预设的模拟数据:

import { describe, test, expect, beforeEach, vi } from 'vitest'
import { setActivePinia, createPinia } from 'pinia'
import { useProjectStore } from '@/stores/project'
import axios from '@/utils/axios'; // 导入路径需和store中一致

// 模拟axios模块
vi.mock('@/utils/axios', () => ({
    default: {
        get: vi.fn()
    }
}))

describe('Projects', () => {
    let store = null
  
    beforeEach(() => {
      setActivePinia(createPinia())
      store = useProjectStore()
      // 每次测试前重置mock,避免用例间干扰
      axios.get.mockReset()
    })

    test('初始状态下projects为空数组', () => {
        expect(store.projects).toEqual([])
    })

    test('调用getAllProjects后projects被填充为3条数据', async () => {
      // 模拟axios.get返回3条项目数据
      axios.get.mockResolvedValue({
          data: [
              { id: 1, name: '项目1' },
              { id: 2, name: '项目2' },
              { id: 3, name: '项目3' }
          ]
      })

      await store.getAllProjects()
      
      expect(axios.get).toHaveBeenCalledWith('projects', { timeout: 15000 })
      expect(store.projects).toHaveLength(3)
    })
})

关键说明

  • mock路径匹配:模拟axios时,导入路径必须和store中@/utils/axios完全一致,否则mock不会生效。
  • 重置mock:在beforeEach中调用mockReset(),避免不同测试用例的mock状态互相干扰。
  • finally块重置loading:使用finally确保无论请求成功或失败,loading状态都会被重置,避免状态不一致。

内容的提问来源于stack exchange,提问作者Dogukan Kalemli

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.18 14:02:47