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
相关产品推荐
相关产品推荐

