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

Vue项目用Sinon模拟$http编写API单元测试遇阻求助

解决Vue.js API封装方法的Sinon Mock测试问题

首先假设你的apiList.ts是如下常见结构(基于Vue原型的$http封装):

import Vue from 'vue';

export const getUsers = () => {
  return Vue.prototype.$http.get('/api/users');
};

export const addUser = (user: any) => {
  return Vue.prototype.$http.post('/api/users', user);
};

export const updateUser = (id: number, user: any) => {
  return Vue.prototype.$http.put(`/api/users/${id}`, user);
};

以下是能正确Mock$http并执行所有日志的测试用例(以Jest+Sinon为例,Mocha+Chai可直接替换断言逻辑):

import Vue from 'vue';
import sinon from 'sinon';
import { getUsers, addUser, updateUser } from './apiList';

describe('API List 单元测试', () => {
  let httpGetStub: sinon.SinonStub;
  let httpPostStub: sinon.SinonStub;
  let httpPutStub: sinon.SinonStub;

  // 每个测试前初始化Mock
  beforeEach(() => {
    // 创建带Stub的Mock $http对象
    const mockHttp = {
      get: sinon.stub().resolves({ data: [{ id: 1, name: 'test' }] }),
      post: sinon.stub().resolves({ data: { id: 2, name: 'new' } }),
      put: sinon.stub().resolves({ data: { id: 1, name: 'updated' } })
    };
    // 替换Vue原型上的$http
    Vue.prototype.$http = mockHttp;
    // 保存Stub引用方便后续断言
    httpGetStub = mockHttp.get;
    httpPostStub = mockHttp.post;
    httpPutStub = mockHttp.put;
  });

  // 每个测试后恢复原始状态,避免污染其他测试
  afterEach(() => {
    delete Vue.prototype.$http;
    sinon.restore();
  });

  test('getUsers 应正确调用$http.get', async () => {
    console.log('step1');
    const result = await getUsers();
    console.log('step2');
    
    // 断言请求方法和URL正确
    expect(httpGetStub.calledOnceWith('/api/users')).toBe(true);
    console.log('step3');
    expect(result.data.length).toBe(1);
    console.log('step4');
  });

  test('addUser 应正确调用$http.post', async () => {
    console.log('step5');
    const testUser = { name: 'new user' };
    const result = await addUser(testUser);
    console.log('step6');
    
    expect(httpPostStub.calledOnceWith('/api/users', testUser)).toBe(true);
    expect(result.data.name).toBe('new');
    console.log('step7');
  });

  test('updateUser 应正确调用$http.put', async () => {
    const testUserId = 1;
    const updatedData = { name: 'updated user' };
    await updateUser(testUserId, updatedData);
    
    expect(httpPutStub.calledOnceWith(`/api/users/${testUserId}`, updatedData)).toBe(true);
  });
});

关键问题修复点

  1. 必须用await处理异步请求:你的日志step3、5不执行,很大概率是没await异步的API方法,导致测试直接结束,后续代码无法执行。
  2. Mock对象要替换到正确的位置:确保替换的是Vue.prototype.$http而非Vue.$http,这是原型挂载的核心点。
  3. Stub需处理异步Promise:用resolves()模拟请求成功的响应,让await能正确拿到结果,避免Promise一直pending。
  4. 测试前后的状态隔离:用beforeEach和afterEach分别初始化Mock和恢复原始Vue原型,防止测试用例间相互污染。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.20 10:20:15