Redux 传奇测试用例 - jest.spyOn

Redux saga test case - jest.spyOn

对于使用 jest.spyOn() 和 mockImplmentation 的模拟 api 调用,我得到 undefined 作为响应。

Saga.tsx

export function* parseUserData(parsingAction: IParsingAction) {

try {
    const skills = yield call(SkillRepository.getAllSkills);

    console.log('------skils-----', skills);    // undefined

    const industries = yield call(IndustryRepository.getAllIndustry);

    if (skills.skillGroup && industry.industryGroup) 
      {

        yield put(getSkillsSuccess(skills.skillGroups));
        yield put(getIndustriesSuccess(industry.industryGroups));

      } 

    else 
   {
       yield put(bulkUploadError());
   }

    } catch (error) {

    yield put(bulkUploadError());

}

}

Saga.test.tsx

describe('ParseUserData job saga', () => {
const action = {
    type: bulkUploadActionType.GET_API_DATA,
    payload: {
        sheetData: {},
        isAdvisor: true,
    },
};
const generator = parseUserData(action);
it('Should call skill repository', () => {
    const skills = { skillGroups: [] };
    const spy = jest.spyOn(SkillRepository, 'getAllSkills');
    spy.mockImplementation((): any => {
        return (skills);
    });
    expect(generator.next().value).toEqual(call(SkillRepository.getAllSkills));
    spy.mockRestore();
});

});

如有任何帮助,我们将不胜感激。它非常简单,但我坚持这个。

将 sagas 作为纯生成器进行测试时,redux saga 中间件未连接以驱动生成器 - 您必须自己执行此操作。所以 SkillRepository.getAllSkills 实际上并没有被调用,相反你需要提供期望值给 generator.next()。您可以在测试部分的第一个示例中看到这一点,其中调用 gen.next(chooseColor(color)) 来驱动发电机。在你的情况下,你会做类似的事情:

expect(generator.next().value).toEqual(call(SkillRepository.getAllSkills));
expect(generator.next(skills).done).toBe(true);

因为真正执行 call 效果的是 redux saga 中间件,如果你想测试当你的 saga 是 运行 时调用 SkillRepository.getAllSkill 你需要按照 Testing the full Saga 下的示例,其中 runSaga 用于让 redux-saga 驱动发电机,您可以在模块上 mock/spy 查看它们是否被调用。

所以我会将您的测试重写为:

it('Should call skill repository', () => {
    const skills = { skillGroups: [] };
    const spy = jest.spyOn(SkillRepository, 'getAllSkills');
    spy.mockImplementation((): any => {
        return (skills);
    });
    runSaga(
      {dispatch: () => {}, getState: () => ({})}, // flesh these out if need be
      parseUserData, action
    ).toPromise().then(() => {
      expect(SkillRepository.getAllSkills.mock.calls.length).toBe(1);
      spy.mockRestore();
    )
});

编辑

对于上面分享的完整 saga 的单元测试:

describe('ParseUserData job saga', () => {
const action = {
    type: bulkUploadActionType.GET_API_DATA,
    payload: {
        sheetData: {},
        isAdvisor: true,
    },
};
const generator = parseUserData(action);
it('Should call skill repository', () => {
    const skills = { skillGroups: [] };
    const industries = { industryGroups: [] };

    expect(generator.next().value).toEqual(
      call(SkillRepository.getAllSkills));
    expect(generator.next(skills).value).toEqual(
      call(IndustryRepository.getAllIndustry));
    expect(generator.next(industries).value).toEqual(
      put(getSkillsSuccess(skills.skillGroups)));
    expect(generator.next().value).toEqual(
      put(getIndustriesSuccess(industries.industryGroups))
    );
    expect(generator.next().done).toBe(true);

});