反应测试;如何模拟componentDidMount或覆盖它?

时间:2015-08-10 16:03:55

标签: unit-testing testing mocking reactjs

我正在尝试测试反应组件。

var Component = React.createClass({

  componentDidMount: function () {

    return this.setState({
      name: 'blabla'
    });
  },

  render: function () {

    return (
      <h1>{this.state.name}</h1>
    );
  }
});

在测试过程中,有没有办法模拟componentDidMount返回或做什么?这将让我自己测试它,只测试组件渲染行为。

谢谢!

3 个答案:

答案 0 :(得分:6)

我更喜欢以下方法,但需要使用ES6类。

// component.jsx
class Component extends React.Component {
    componentDidMount() { return this.setState({name: 'blabla'}); }
    render() { return (<h1>{this.state.name}</h1>); }
}

//component-spec.jsx
describe('Component', () => {
    it('does stuff', () => {
        let ComponentTest = class extends Component {
            componentDidMount() { 
                // your override here
            }
        };
        let component = TestUtils.renderIntoDocument(<ComponentTest />);
        //expect(component...).toEqual(...)
    });
});

重点是创建一个继承OriginalClass的按需ChildClass, 做任何覆盖,然后TestUtils.renderIntoDocument(<ChildClass />)

答案 1 :(得分:2)

如果我理解正确的话,这里的想法是你在测试中呈现组件之前尝试存根函数。在您的情况下,componentWillMount仅在组件的生命周期中被调用一次,紧接在呈现组件之前。所以你不能只渲染组件而然后存根该函数,它必须在渲染发生之前完成。

我们以这些组件为例:

<强> parent.js

var Child = require('./child.js');
var Parent = React.createClass({
    render : function () {
        return (
            <div className="parent">
                <Child/>
            </div>
        );
    }
});
module.exports = Parent;

<强> child.js

var Child = React.createClass({
    test : function () {
        return true;
    },
    render : function () {
        if (this.test) {
            throw('boom');
        }
        return (
            <div className="child">
                Child
            </div>
        );
    }
});
module.exports = Child;

在这里,我们希望在呈现Child组件之前存根test函数,否则它会爆炸。

我可以使用jasmine-react执行此操作。这些辅助函数在运行测试时提供了一些有用的功能,几乎到了TestUtils可以完全抛弃的程度。

jasmineReact.render(component, [container])会将component的实例呈现到[container]中指定的DOM节点中。这类似于TestUtils.renderIntoDocument(),除了它将组件呈现为附加的DOM节点而不是分离的DOM节点。测试完成后,它还将执行必要的清洁操作。

jasmineReact.spyOnClass(componentClass, functionName)将存根属于组件类的特定函数。此行为一直持续到测试结束,这意味着您可以在呈现组件之前调用此函数。如果我理解正确的话,这就是你要找的东西。

所以,使用这两个辅助函数,我可以为上面显示的代码编写一个测试,看起来像这样:

var React = require('react/addons'),
    Parent = require('./parent.js'),
    Child = require('./child.js'),
    jasmineReact = require('jasmine-react-helpers');

describe('Parent', function () {
    it('does not blow up when rendering', function () {
        jasmineReact.spyOnClass(Child, 'test').and.returnValue(false);
        var parentInstance = jasmineReact.render(<Parent/>, document.body); //does not blow up
        expect(parentInstance).toBeTruthy(); //passes
    });
});

如果您有任何问题,请与我们联系。

答案 2 :(得分:1)

我发现了两种方法(我相信还有更多)。

1)我在基本元素类中使用了sinon-chai并且必需,然后使用rewireifycomponentWillMount方法上设置一个间谍集。这有效,但不确定您正在使用哪些测试套件。

2)可能更简单的方法。只是使用TestUtils获取组件的实例,然后只需手动运行componentWillMount方法。

第二种方式可能看起来像(原谅pesudo代码):

it('should call state when it first mounts', function () {
  var Component = require('../my-component');
  var component = TestUtils.renderIntoDocument(<Component />);

  component.setState({name: null});
  component.componentWillMount();

  expect(component.state.name).to.equal('blabla');
});