我的项目中有一个非常复杂的选择器结构(某些选择器可能具有多达5个嵌套层),因此其中一些很难通过传递输入状态进行测试,而我想模拟输入选择器。但是我发现这是不可能的。

这是最简单的示例:

// selectors1.js
export const baseSelector = createSelector(...);

--
// selectors2.js
export const targetSelector = createSelector([selectors1.baseSelector], () => {...});

我想在测试套件中拥有什么:
beforeEach(() => {
  jest.spyOn(selectors1, 'baseSelector').mockReturnValue('some value');
});

test('My test', () => {
  expect(selectors2.targetSelector()).toEqual('some value');
});

但是,这种方法不起作用,因为在初始化targetSelector期间selectors1.baseSelector正在获取selectors2.js的引用,并在其后将模拟分配给selectors1.baseSelector

我现在看到2种可行的解决方案:
  • 使用selectors1.js模拟整个jest.mock模块,但是,如果在某些特定情况下需要更改selectors1.baseSelector输出,它将无法正常工作
  • 像这样包装每个依赖选择器:

  • export const targetSelector = createSelector([(state) => selectors1.baseSelector(state)], () => {...});
    

    但是出于显而易见的原因,我不太喜欢这种方法。

    因此,接下来的问题是:是否有机会模拟重新选择选择器以进行单元测试?

    最佳答案

    事实是,重新选择基于组合概念。因此,您可以从许多其他选择器中创建一个选择器。您真正需要测试的不是整个选择器,而是完成工作的最后一个函数。如果没有,则测试将彼此重复,就像您对选择器1进行了测试,并且在选择器2中使用了选择器1一样,然后自动在选择器2测试中对它们都进行了测试。

    为了要达到:

  • 少玩笑
  • 无需特别模拟组合选择器
  • 的结果
  • 没有测试重复

  • 仅测试选择器的结果功能。可以通过selector.resultFunc访问。

    因此,例如:
    const selector2 = createSelector(selector1, (data) => ...);
    
    // tests
    
    const actual = selector2.resultFunc([returnOfSelector1Mock]);
    const expected = [what we expect];
    expect(actual).toEqual(expected)
    

    概括

    我们无需测试整个组合,复制相同的断言或模拟特定的选择器输出,而无需测试定义选择器的函数,因此可以通过resultFunc键访问createSelector中的最后一个参数。

    09-05 22:14
    查看更多