新测试和React Redux,所以我可能会在这里混淆一些问题。我只会提供一个示例,但我尝试了mount()
,shallow()
,instance()
,stub
,spy
等多种不同的组合。
给定一个组件,其中setFooData()
更新redux状态和Foo.props.data
:
const mapDispatchToProps = (dispatch, props) => ({
setFooData(fooId, data) {
dispatch(Actions.setFooData(fooId, data));
},
});
...
return (
<div fooId={this.props.fooId}>
<Foo {...fooProps}/>
</div>
);
我想围绕调用setFooData()
的条件编写一些测试,即componentDidMount()
和componentWillReceiveProps()
等生命周期方法中的条件。
因为setFooData()
涉及服务器调用等等,并且因为这些测试仅涉及视图层以及Foo.props.data
最终由setFooData()
setFooData()
设置而导致组件呈现的方式,{{ 1}}似乎是stub
的好候选人。
因此,酶shallow()
而不是mount()
似乎合适,对吗?在任何情况下,当我尝试stub
setFooData()
时:
let wrapper = return shallow(<Foo {...props}/>);
let stub = sinon.stub(wrapper.instance(), 'setFooData');
我收到错误:
Attempted to wrap undefined property setFooData as function
经过检查,wrapper.instance()
会产生一个确实没有定义setFooData()
的对象,但根据其他例子,我认为应该是这样。
此外,setFooData()
确实存在wrapper.instance().selector.props
,而let stub = sinon.stub(wrapper.instance().selector.props, 'setFooData');
虽然避免了错误,但当我检查对象setFooData() =/= stub
时,并没有根据测试
当我使用mount()
时,
let wrapper = mount(<Provider store={store}><Foo {...props}/></Provider>);
let componentDidMountSpy = sinon.spy(Foo.prototype, 'componentDidMount');
let componentWillReceivePropsSpy = sinon.spy(Foo.prototype, 'componentWillReceiveProps');
expect(componentDidMountSpy.called).to.be.true; //passes
expect(componentWillReceivePropsSpy.called).to.be.true; //passes
expect(stub.called).to.be.true; //fails
我收到一个与setFooData()
正文相关的错误,因此setFooData()
被调用,但该函数实际上并未存根,以防止其实体被执行。
感谢您提供任何帮助以澄清我的理解。
答案 0 :(得分:1)
我认为你正走最艰难的道路。您应该单独测试组件,而不是connect
ed组件。如果您测试connect
ed组件,那么您正在进行集成测试并进行connect
确实有效的双重测试。那已经在你的react-redux中测试了。
相反,在单元测试中自行测试您的动作创建者。 然后,将组件导出为名为export而不连接,并使用连接版本的默认导出。
这样你就可以简单地导入pure-React版本并将你想要的任何东西作为道具传递,以便以后轻松断言。
如果您需要专门测试这些生命周期方法中发生的事情,可以从instance
调用这些方法:
const fakeActionCreator = sinon.spy()
const subject = mount(<MyComponent doSomething={ fakeActionCreator } />)
subject.instance().componentDidMount()
assert.equal(fakeActionCreator.callCount, 1)