当有函数不使用 'yield' 或 'call' 或 'put' 等效果时如何测试 sagas?

How to test sagas when there are functions not using 'yield' or an effect like 'call' or 'put'?

在所有示例中,我发现每个人都在他们的 sagas 中使用 yield call()yield put() 等。现在我有一个 saga,它只执行一个函数而不使用 yield call()。此函数在 select 效果之后和调用效果之前执行(请参阅下面的代码了解 service 变量。此函数 returns 是 class 的实例,它不是网络请求或承诺。

传奇工作正常,但我不确定如何像这样测试它。在使用 redux-sagas-test-plan 时效果很好,但是一旦我删除了效果(我从 .provide() 中删除了该效果,测试就会失败。

传奇

export function* getDetails() {
    try {
        const config = yield select(getProperties());
        const service = getService(config);
        const data = yield call([service, service.getDetails]);
        yield put(success(data));
    } catch(e) {
        yield put(failure());
    }
}

测试

import { getDetails as detailsSaga } from '...';
const data = {};

it('should succeed getting details', async () => {
        await expectSaga(detailsSaga)
            .provide([
                [select(getProperties), {}],
                [call([serviceMock, serviceMock.getDetails]), data]
            ])
            .put(success(data))
            .dispatch(fetchDetails())
            .silentRun();
    });

测试的预期结果是让 success(data) 创建者执行,但我得到 failure() 创建者作为实际值。

Expected
    --------
    { '@@redux-saga/IO': true,
      combinator: false,
      type: 'PUT',
      payload: 
       { channel: undefined,
         action: 
          { type: 'FETCH_DETAILS_SUCCESS',
            data: { } } } }

    Actual:
    ------
    1. { '@@redux-saga/IO': true,
      combinator: false,
      type: 'PUT',
      payload: 
       { channel: undefined,
         action: { type: 'FETCH_DETAILS_FAILURE' } } }

任何时候在 saga 中调用函数,都应该使用 call 效果。最好使用它而不是像您所做的那样直接调用该函数。它会 return 与您直接调用它时相同的数据,并且会使测试更容易,因为您不必模拟或监视任何东西。

示例:

export function* getDetails() {
    try {
        const config = yield select(getProperties());
        const service = yield call(getService, config);
        const data = yield call([service, service.getDetails]);
        yield put(success(data));
    } catch(e) {
        yield put(failure());
    }
}

根据我找到的其他示例,这是我的解决方案:

import { call } from 'redux-saga-test-plan/matchers';

beforeEach(() => {
  service = getService({});
  data = { /* ... */ });
});

it('should succeed getting details', async () => {
  await expectSaga(detailsSaga)
    .provide([
      [select(getProperties), {}],
      [call.fn(service.getDetails), data]
    ])
    .put(success(data))
    .dispatch(fetchDetails())
    .silentRun();
});

我必须使用 redux-saga-test-plan/matchers 的调用效果并创建一个由 getService 返回的实际实例。由于某种原因,模拟在这里不起作用。

我不太清楚为什么这样做的细节,但我写下这个答案是为了以防万一有人试图实现这一点。注意:我同意另一个答案,所有函数都应该使用 yield call 调用,但我被要求不要在这里这样做。