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

Setup语法Pinia Store测试:如何同时Mock计算属性并统计方法调用

Setup语法Pinia Store测试:同时Mock计算属性与统计方法调用

问题

用Setup语法编写Pinia Store,结合@pinia/testing和Vitest测试时遇到矛盾:

  • 使用createTestingPinia可以直接Mock计算属性,但无法统计内部方法的调用次数
  • 仅使用createPinia能统计方法调用,却无法便捷Mock计算属性

尝试过的操作:

  • 仅用createPinia时,通过store.someComputedField = computed(() => 1)Mock计算属性
  • 使用createTestingPinia时,通过store.someComputedField = 1Mock计算属性,但此时方法调用统计失效

由于Store内部方法会调用同Store的计算属性,需要同时实现Mock计算属性和统计方法调用两个需求,且标准Options语法Store无此问题。

相关代码

测试代码

describe.only('TestStore', () => {
    beforeEach(() => {
        setActivePinia(
            createTestingPinia({
                stubActions: false,
                createSpy: vi.fn,
            })
        );
        vi.clearAllMocks();
    });

    test('Is it possible to mock computed properties and still count action calls?', async () => {
        const testStore = useTestStore();

        vi.spyOn(testStore, 'method1');
        testStore.computedProp = 1;

        expect(testStore.method2()).toBe(1);
        expect(testStore.method1).toHaveBeenCalledOnce();
    });
});

Store代码

export const useTestStore = defineStore('test-store', () => {
    const computedProp = computed(() => 1);

    const method1 = () => {
        return computedProp.value;
    };

    const method2 = () => {
        return method1();
    };

    return {
        method2,
        method1,
        computedProp,
    };
});

错误信息

AssertionError: expected "spy" to be called once, but got 0 times

原因

Setup语法的Store中,method2直接调用的是闭包内定义的method1函数,而非Store实例上的method1引用。你通过vi.spyOn(testStore, 'method1')给Store实例的方法加了监听,但内部调用的是闭包中的原始函数,因此监听无法捕获到调用次数。

解决方案

方案1:调整Store写法,让内部方法通过实例调用

修改Store代码,让方法间的调用指向Store实例上的方法,而非闭包内的函数:

export const useTestStore = defineStore('test-store', () => {
    const computedProp = computed(() => 1);

    // 先声明空store对象
    const store = {};

    // 给store挂载方法,内部调用也指向store实例
    store.method1 = () => {
        return computedProp.value;
    };

    store.method2 = () => {
        return store.method1();
    };

    store.computedProp = computedProp;

    return store;
});

此时原测试代码即可正常工作:createTestingPinia可以Mock计算属性,vi.spyOn也能捕获到method1的调用次数。

方案2:使用createPinia,Mock计算属性的getter

无需修改Store,改用createPinia,通过监听计算属性的value getter来Mock值,同时统计方法调用:

describe.only('TestStore', () => {
    beforeEach(() => {
        const pinia = createPinia();
        setActivePinia(pinia);
        vi.clearAllMocks();
    });

    test('Mock computed and count method calls', async () => {
        const testStore = useTestStore();

        // Mock计算属性的getter
        vi.spyOn(testStore.computedProp, 'value', 'get').mockReturnValue(1);
        // 监听method1调用
        vi.spyOn(testStore, 'method1');

        expect(testStore.method2()).toBe(1);
        expect(testStore.method1).toHaveBeenCalledOnce();
    });
});

这个方案保留了Setup Store的原始写法,同时满足两个测试需求。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.26 07:45:26