redux-saga-test-plan测试:两次调用selector无法返回不同模拟值
Redux-Saga-Test-Plan 重复调用同一Selector的Mock响应问题
问题场景
编写Saga时两次调用同一个selector,使用redux-saga-test-plan的provide方法测试时,期望两次调用分别返回mockResponseOne和mockResponseTwo,但实际第二次调用始终返回第一次的mockResponseOne,无法获取预期值。
Saga代码示例
export function* mySaga(url) { // ...其他逻辑 yield Effects.call(handleRequest, url); const responseOne = yield Effects.select(selectResponse); if (responseOne.status === "failed") { yield Effects.call(handleRequest, responseOne.url); const responseTwo = yield Effects.select(selectResponse); console.log(responseTwo) // 测试时此处接收的是responseOne // ...其他逻辑 } }
测试代码示例
import {expectSaga} from "redux-saga-test-plan"; import * as matchers from "redux-saga-test-plan/matchers"; it("should the console.log print mockResponseTwo", async () => { await expectSaga( mySaga, mockUrl, ) .provide([ [matchers.call.fn(handleRequest), mockResponseOne], [select(selectResponse), mockResponseOne], [matchers.call.fn(handleRequest), mockResponseTwo], [select(selectResponse), mockResponseTwo], // 此处响应未更新 ]) .call(handleRequest, mockUrl) .call(handleRequest, mockResponseOne.url) });
问题原因
redux-saga-test-plan中,使用静态值的匹配器(如[select(selectResponse), mockResponseOne])时,每次匹配到该effect都会返回同一个静态值,重复添加相同的匹配器不会按顺序触发,无法实现多次调用返回不同值的需求。
解决方法
方法1:使用函数动态返回值
通过维护调用计数器,在函数中根据调用次数返回对应的值:
import {expectSaga} from "redux-saga-test-plan"; import * as matchers from "redux-saga-test-plan/matchers"; import {select} from 'redux-saga/effects'; it("should the console.log print mockResponseTwo", async () => { let selectInvokeCount = 0; await expectSaga(mySaga, mockUrl) .provide([ // 根据handleRequest的调用参数返回对应结果 [matchers.call.fn(handleRequest), (callEffect) => { return callEffect.args[0] === mockUrl ? mockResponseOne : mockResponseTwo; }], // 根据调用次数返回不同的selector结果 [select(selectResponse), () => { selectInvokeCount++; return selectInvokeCount === 1 ? mockResponseOne : mockResponseTwo; }] ]) .call(handleRequest, mockUrl) .call(handleRequest, mockResponseOne.url) .run(); });
方法2:使用matchers.sequence按顺序返回值
利用redux-saga-test-plan提供的sequence匹配器,指定按调用顺序返回的响应数组:
import {expectSaga} from "redux-saga-test-plan"; import * as matchers from "redux-saga-test-plan/matchers"; import {select} from 'redux-saga/effects'; it("should the console.log print mockResponseTwo", async () => { await expectSaga(mySaga, mockUrl) .provide([ // 按顺序返回handleRequest的两次调用结果 [matchers.call.fn(handleRequest), matchers.sequence([mockResponseOne, mockResponseTwo])], // 按顺序返回selector的两次调用结果 [select(selectResponse), matchers.sequence([mockResponseOne, mockResponseTwo])] ]) .call(handleRequest, mockUrl) .call(handleRequest, mockResponseOne.url) .run(); });
方法3:精确匹配调用上下文(可选)
如果需要更精细化控制,可以结合调用参数或上下文精确匹配每次effect:
import {expectSaga} from "redux-saga-test-plan"; import * as matchers from "redux-saga-test-plan/matchers"; import {select} from 'redux-saga/effects'; it("should the console.log print mockResponseTwo", async () => { await expectSaga(mySaga, mockUrl) .provide([ // 第一次调用handleRequest返回mockResponseOne [matchers.call(handleRequest, mockUrl), mockResponseOne], // 第一次调用selector返回mockResponseOne [select(selectResponse), mockResponseOne], // 第二次调用handleRequest返回mockResponseTwo [matchers.call(handleRequest, mockResponseOne.url), mockResponseTwo], // 第二次调用selector返回mockResponseTwo [select(selectResponse), mockResponseTwo] ]) .run(); });
注:此方法需确保每次effect的参数完全匹配,适用于调用参数明确的场景。
内容的提问来源于stack exchange,提问作者Mario Rodeghiero
相关产品推荐
相关产品推荐

