这是一个概括性的例子:
// myActions.js
export const actionOne = () => (dispatch) => {
dispatch(actionTwo());
};
export const actionTwo = () => ({
type: 'SOME_TYPE',
});
我想测试actionTwo
是否已被调用或调度,理想情况下,测试不知道actionTwo
中发生了什么,因为我有一个不同的测试来处理
我正在使用redux-mock-store
将已测试的操作分派给模拟商店并调用store.getActions()
以查明是否已调度thunk action creator中的预期操作。我觉得这不是正确的方式进入这个特定的场景,因为那时测试将测试比它应该更多。我真的只想知道是否已经调用了actionTwo
。
我知道spyOn
和jest.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' }]);
});
});
我很感激任何建议!
答案 0 :(得分:2)
我花了一会儿,但我明白了。这不是理想的(因为它涉及对测试代码的一个小改动),但是我可以得到的最接近理想。
// 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;
那就是它。现在我可以确保忽略导出函数的所有副作用并将其作为实际单位进行测试。
答案 1 :(得分:0)
最好断言两个 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');
});
});