什么时候应该在 Enzyme / React 测试中使用 render 和 shallow?

When should you use render and shallow in Enzyme / React tests?

在 post 提出这个问题之前,我尝试在 sqa stackexchange 中搜索,但我没有找到 post 关于 shallow 和 render 的信息,所以我希望有人能在这里帮助我。

在测试 React 组件时什么时候应该使用 shallow 和 render? 根据airbnb docs,我对两者的区别提出了一些看法:

  1. 由于 shallow 正在测试组件 作为一个单元 ,因此它应该用于 'parent' 组件。 (例如表格、包装器等)

  2. 渲染用于子组件。

我问这个问题的原因是我很难弄清楚我应该使用哪一个(尽管文档说它们非常相似)

那么,我怎么知道在特定情况下使用哪一个?

根据酶 docs:

mount(<Component />) 完整 DOM 渲染非常适合您拥有可能与 DOM api 交互的组件的用例,或者可能需要完整的生命周期才能完全测试组件(即 componentDidMount 等)

对比

shallow(<Component />) 用于浅渲染有助于限制您将组件作为一个单元进行测试,并确保您的测试不会间接断言子组件的行为。

对比

render 用于将 React 组件呈现为 static HTML 并分析生成的 HTML 结构。

您仍然可以在浅层渲染中看到底层的 "nodes",因此例如,您可以使用 AVA 作为规范运行器来执行类似这样(稍微做作的)示例:

let wrapper = shallow(<TagBox />);

const props = {
    toggleValue: sinon.spy()
};

test('it should render two top level nodes', t => {
    t.is(wrapper.children().length, 2);
});

test('it should safely set all props and still render two nodes', t => {
    wrapper.setProps({...props});
    t.is(wrapper.children().length, 2);
});

test('it should call toggleValue when an x class is clicked', t => {
    wrapper.setProps({...props});
    wrapper.find('.x').last().simulate('click');
    t.true(props.toggleValue.calledWith(3));
});

注意渲染设置道具寻找选择器甚至合成事件都支持浅层渲染,所以大多数时候你可以直接使用它。

但是,您将无法获得组件的完整生命周期,因此如果您希望在 componentDidMount 中发生一些事情,您应该使用 mount(<Component />);

此测试使用 Sinon 监视组件的 componentDidMount

test.only('mount calls componentDidMount', t => {

    class Test extends Component {
        constructor (props) {
            super(props);
        }
        componentDidMount() {
            console.log('componentDidMount!');
        }
        render () {
            return (
                <div />
            );
        }
    };

    const componentDidMount = sinon.spy(Test.prototype, 'componentDidMount');
    const wrapper = mount(<Test />);

    t.true(componentDidMount.calledOnce);

    componentDidMount.restore();
});

以上不会通过 shallow renderingrender

render 只会为您提供 html,所以您仍然可以这样做:

test.only('render works', t => {

    // insert Test component here...

    const rendered = render(<Test />);
    const len = rendered.find('div').length;
    t.is(len, 1);
});

希望对您有所帮助!

shallow() 和 mount() 之间的区别在于 shallow() 测试组件与它们呈现的子组件隔离,而 mount() 更深入并测试组件的子组件。

对于 shallow() 这意味着如果父组件渲染了另一个渲染失败的组件,那么父组件上的 shallow() 渲染仍然会通过。