如何模拟实际上是 Redux 的连接动作创建者的道具?

How to mock props that actually are connected action creators of Redux?

在集成测试中,我想测试连接的动作创建器是否被调用。

describe('SomeContainer', () => {
  let subject, store, fancyActionCreator

  beforeEach(() => {
    store = createStore(combineReducers({ /* ... */ }))
    fancyActionCreator = sinon.spy()
    const props = {
      fancyActionCreator
    }
    subject = (
      <Provider store={store}>
        <SomeContainer {...props} />
      </Provider>
    )
  })

  it('calls fancyActionCreator on mount', () => {
    mount(subject)
    expect(fancyActionCreator.callCount).to.equal(1)
  })
}

动作创建器在 componentWillMount 内部调用,并在测试环境之外按预期工作。

问题是原始动作创建者在测试中被调用并且没有被正确地模拟掉。

我感觉这是因为 Redux 的 connect() 方法取代了 spy:

connect(mapStateToProps, { fancyActionCreator })(SomeContainer)

您使用商店安装了您的组件。如果您从 mount 调用中获取 return 值,它会为您提供反应元素的酶包装器。此包装器可用于针对商店分派操作:

const enzymeWrapper = mount(subject)
enzymeWrapper.node.store.dispatch({ type: "ACTION", data: "your fake data" });

但这是更多集成类型的测试,因为您正在使用 reducer 以及 Redux 存储状态与您的属性的连接。

这是我唯一可以用来测试 Redux 存储状态与组件属性的连接的测试。如果你以其他方式伪造属性,你可能会覆盖你的组件逻辑,但你缺少将属性连接到存储的部分。

我建议将您的组件分为展示组件和容器组件。 Presentational 不需要使用 store,因此您可以通过传递不同的属性来敲打它的逻辑。容器组件关注的是将商店连接到展示组件。因此,对于容器组件,您将使用我描述的测试类型。

对评论的反应:

实际上 presentational/unconnected 组件的 mountshallow 的用法并不是那么简单。有时,您在展示组件上使用需要由挂载呈现的子组件(例如,react-select 出于某种原因需要 DOM)。

但通常是的,人们应该努力将 shallow 用于表示组件,除非您意识到自己需要 mount :)。