如果 thunk 动作创建者中的 thunk 动作已被调度,我如何检查一个笑话测试?

Posted

技术标签:

【中文标题】如果 thunk 动作创建者中的 thunk 动作已被调度,我如何检查一个笑话测试?【英文标题】:How can I check in a jest test if a thunk action within a thunk action creator has been dispatched? 【发布时间】:2018-01-04 19:14:59 【问题描述】:

这是一个通用的例子:

// myActions.js
export const actionOne = () => (dispatch) => 
    dispatch(actionTwo());
;

export const actionTwo = () => (
    type: 'SOME_TYPE',
);

我想测试 actionTwo 是否已被调用或分派,理想情况下,测试不知道 actionTwo 中发生了什么,因为我有一个不同的测试来处理这个问题。

我正在使用redux-mock-store 将经过测试的操作分派到模拟商店并调用store.getActions() 以查明是否已分派了thunk 操作创建器中的预期操作。我觉得在这种特殊情况下这不是正确的方法,因为那样测试会比它应该测试的更多。我真的只想知道actionTwo 是否被调用过。

我知道spyOnjest.mock,但我无法使用它们来解决我的问题。这是广义测试的样子:

// myActions.test.js
import configureMockStore from 'redux-mock-store';
import thunk from 'redux-thunk';
import * as actions from 'myActions';

const mockStore = configureMockStore([thunk]);

test('actionOne', () => 
    const store = mockStore();

    return store.dispatch(actions.actionOne()).then(() => 
        // TODO: check if actions.actionTwo was called
    );
);

test('actionTwo', () => 
    const store = mockStore();

    return store.dispatch(actions.actionTwo()).then(() => 
        expect(store.getActions()).toEqual([ type: 'SOME_TYPE' ]);
    ); 
);

感谢您的任何建议!

【问题讨论】:

【参考方案1】:

花了我一段时间,但我想通了。这并不理想(因为它涉及对测试代码的小改动),但我能得到的最接近理想。

// myActions.js
export const actionOne = () => (dispatch) => 
    dispatch(exports.actionTwo());
;

export const actionTwo = () => (
    type: 'SOME_TYPE',
);

重要的变化是exports.actionTwo()。这样,我确保我可以从外部(测试文件)覆盖函数的实现,并且实际上会从导入的文件中调用覆盖函数。

现在我可以简单地将如下内容添加到我的测试文件中:

beforeEach(() => 
    actions.actionTwo = jest.fn(() => () => Promise.resolve());
);

actionTwo 现在被嘲笑,我可以使用toBeCalledWith 和其他期望。如果我想在同一个测试文件中测试它的实际实现,我可以在调用beforeEach之前将它存储在一个变量中,比如:

const actionTwo = actions.actionTwo;

然后在其实现的测试设置中,我可以覆盖模拟调用

actions.actionTwo = actionTwo;

就是这样。现在我可以确保忽略导出函数的所有副作用,并将其作为实际单元进行测试。

【讨论】:

【参考方案2】:

最好断言两个 redux 动作 进入商店,而不是 actionOne 调用动作创建者。

因为所有派发到商店的动作都必须有一个动作type。只需断言store.getActions()

test('actionOne', () => 
    const store = mockStore();
    return store.dispatch(actions.actionOne()).then(() => 
        expect(store.getActions()).to.have.length(2);
        expect(store.getActions()[0].type).to.equal('ACTION_ONE_TYPE');
        // make additional assertions about the first action

        expect(store.getActions()[1].type).to.equal('ACTION_TWO_TYPE');
    );
);

【讨论】:

感谢您的回复,但我不相信这是正确的方法。想象一下actionTwo 不是一个简单的动作创建者,而是一个 thunk,调度自己的动作,甚至可能有条件地调度。我不想知道actionOne 测试中的任何逻辑,我只想确保actionTwo 完全被调度,甚至只是函数被调用。没有简单的方法可以实现吗? 同意。我不想测试动作的实现(它在别处测试过),我只想测试它是否被调用。

以上是关于如果 thunk 动作创建者中的 thunk 动作已被调度,我如何检查一个笑话测试?的主要内容,如果未能解决你的问题,请参考以下文章

Thunk 动作创建者派出另一个 thunk 动作创建者,但 typescript 抛出错误。我应该添加啥类型?

使用 redux-thunk 从 React Native 中的动作创建者返回 Promise

如何键入 Redux thunk 动作创建者以返回承诺

调度 thunk 动作创建者在 TypeScript 中不匹配

Redux thunk:如何等待异步操作的完成

Redux-Thunk - 异步动作创建者承诺和链接不起作用