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

从Jest迁移至Vitest时vi.mock生命周期引发测试报错问题

Jest迁移Vitest:第二个测试用例vi.spyOn报错"setInput does not exist"的解决方案

问题根源

问题核心在于vi.restoreAllMocks()在Vitest和Jest中的行为差异:

  • Jest的restoreAllMocks仅清除mock的调用记录,不会改动mock的实现逻辑
  • Vitest的vi.restoreAllMocks()会完全重置所有mock的实现,包括你通过vi.mock定义的MockStep的mockImplementation。第一个测试执行后,afterEach里的restoreAllMocks把MockStep的构造函数打回原形,导致第二个测试时new MockStep()返回空对象,自然找不到setInput方法。

修复方案

最简洁的解决方式是把vi.restoreAllMocks()换成vi.clearAllMocks():

  • vi.clearAllMocks()只会清除mock的调用记录、实例和结果,不会改动mock的实现逻辑,刚好匹配你的测试需求。

修改后的代码

import {describe, beforeEach, afterEach, test, expect, vi} from "vitest";
import {Step as MockStep} from "../step";

vi.mock("../step", () => {
    return {
        Step: vi.fn().mockImplementation(() => {
            return {
                setInput() {},
            };
        }),
    };
});

describe("Step", () => {
    let step;

    beforeEach(() => {
        step = new MockStep();
    });

    afterEach(() => {
        // 替换为clearAllMocks,只清调用记录不重置实现
        vi.clearAllMocks();
    });

    test("first", () => {
        vi.spyOn(step, "setInput");

        expect(true).toBe(true);
    });

    test("second", () => {
        vi.spyOn(step, "setInput"); // 现在可正常执行

        expect(true).toBe(true);
    });
});

备选方案(若必须用restoreAllMocks)

如果你的测试场景确实需要保留vi.restoreAllMocks(),可以在beforeEach里重新绑定mock实现,避免被重置:

describe("Step", () => {
    let step;

    beforeEach(() => {
        // 每次测试前重新设置mock实现
        MockStep.mockImplementation(() => {
            return {
                setInput() {},
            };
        });
        step = new MockStep();
    });

    afterEach(() => {
        vi.restoreAllMocks();
    });

    // ...测试用例不变
});

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.29 11:52:54