假设我有一个经典的redux结构:动作、组件、容器、reducers。
我这里用的是一个弹出式的例子
对于 行动 我会的。
closePopup () {
return { type: this.actionTypes.CLOSE_POPUP };
}
close () {
return (dispatch) => {
dispatch(this.closePopup());
dispatch(otherAction());
}
}
组件:
...
<button onClick={this.props.onClose()} />
...
容器:
const mapDispatchToProps = (dispatch) => ({
onClose () {
dispatch(popupActions.close());
},
});
reducer:
case actionTypes.CLOSE_POPUP:
return {
...state,
isClosed: true,
};
所以这是一个经典的工作流程。我有一个按钮,它从容器中调用了一个方法,这个方法调用了 close()
方法,并派发了一些方法,其中一个方法派发了一个改变状态的动作。
我想测试一下 onClose
方法改变了我所期望的状态。
作为一个例子,它应该是这样的。
describe('close', () => {
it('should change state', () => {
// expect(container.onClose()) to change state to { isClosed: true }
})
})
我如何才能做到这一点呢? 这是用redux测试的常见模式吗? 因为我似乎找不到例子。
对于 close
动作,我只测试它是否派遣了另外两个动作--因为这就是它真正的作用。正如有人在你的帖子的评论中所解释的那样,一个动作创建者的单元测试不应该忽略这个函数的实际作用。
不过,当你在 Jest 中尝试这样做时,你会遇到一个问题(或者任何测试库都有可能),如果子动作是写在与 close
,不可能轻易的把他们嘲讽出来。
为什么要把它们模拟出来呢?它们可能比较复杂,自己会改变状态,而且也有自己专门的单元测试,所以在这个不相关的测试中调用原来的函数不是一个好主意。
但是有一个巧妙的技巧,你可以导入动作创建模块 在同一模块中,并使用该导入的模块引用来调度其他动作。
import thisModule from './this_action_creator_module';
export const close = () => {
return (dispatch) => {
dispatch(thisModule.closePopup());
dispatch(thisModule.otherAction());
}
}
以这种方式编写,你可以模拟由以下模块导出的特定动作。this_action_creator_module
. 这允许你调用 close
中,并断言它派发了其他两个动作的 mocks(你定义的)。
在我看来,这是单元测试中最复杂的部分。剩下的就是很直接的输入-断言-输出。