在 ES7 中存根 class 字段函数
Stubbing class field-functions in ES7
在我的测试套件中,如何存根 class' 属性,它是一个函数*? 使用常规方法很容易使用 Object.getOwnPropertyNames(component.prototype)
和猴子修补每个找到的方法,但经过长时间的努力,我还没有找到任何方法来提取通过分配给 class' 字段创建的函数。
我的测试堆栈由带有 Jasmine2 和 babel 的 Jest 组成。
转译的问题是arrow-function-properties(当然,正如预期的那样)分配给转译的输出实例"class"(实际上是函数, 当然)。因此,除了实例化该对象之外,我看不到任何对它们进行存根的方法,对吗? Here is the example of input es7 code and the babel's output. 但是我不是特别喜欢这个解决方案,看起来很老套。此解决方案的另一个缺点是我无法直接实例化组件的 class.
(*) 这个问题的背景是单元测试用 es7-like classes 编写的 React 组件,箭头函数分配给 class' 属性以实现自动绑定。
我在为我正在工作的项目编写单元测试时遇到了同样的问题,我认为我找到了一个很好的模式来解决它。希望对您有所帮助:
上下文
这里是一个 React 组件的例子,它有一个使用粗箭头符号定义的方法 handleClick
。
import React, { Component } from 'react';
class Foo extends Component {
componentWillMount() {
this.handleClick();
}
handleClick = (evt) => {
// code to handle click event...
}
render() {
return (
<a href="#" onClick={this.handleClick}>some foo link</a>
);
}
}
问题
如本文所述link Babel 将转译代码,以便 handleClick
方法仅在实例化后可用(检查生成的构造函数的第31到33行)
这里的问题是有时您需要在实例化 class.
之前访问使用粗箭头表示法定义的方法
例如,假设您正在为 componentWillMount
class 方法编写单元测试,并且您想要对 handleClick
进行存根,以便您只测试所需的单元。但是现在你有一个问题,因为你只能在实例化后访问 handleClick
并且 componentWillMount
方法将作为其实例化生命周期的一部分由 React
自动调用。
解决方案
以下是我如何应用一个简单的模式来解决这样的问题:
import React from 'react';
import { mount } from 'enzyme';
import { expect } from 'chai';
import sinon from 'sinon';
import Foo from './foo';
describe('Foo', () => {
describe('componentWillMount method', () => {
const handleClickStub = sinon.stub();
class FooWrapper extends Foo {
constructor(props) {
super(props);
this.handleClick = handleClickStub;
}
}
it('should register a click event listener to the externalElement property', () => {
handleClickStub.reset();
mount(<FooWrapper />);
expect(handleClickStub.calledOnce).to.be.true;
});
});
});
说明
我已将原始 Foo
组件包装到 FooWrapper
中,在初始化原始组件后,在其构造函数中,我将原始 handleClick
方法替换为存根版本,这样我就可以属性 测试我的 componentWillMount
class.
由于 babel 通过 transform-class-properties 在 class 方法上转换箭头函数语法的方式,class 方法不再绑定在原型上,而是绑定在实例上。
使用 Jest 19 的内置断言和 .spyOn 方法,这是我的解决方案:
import React from 'react';
import { shallow } from 'enzyme';
describe('MyComponent', () => {
it('should spy properly', () => {
const wrapper = shallow(<Component />);
const wrapperInstance = wrapper.instance();
const spy = jest.spyOn(wrapperInstance, 'functionName');
wrapperInstance.functionName();
expect(spy).toHaveBeenCalledTimes(1);
})
});
在我的测试套件中,如何存根 class' 属性,它是一个函数*? 使用常规方法很容易使用 Object.getOwnPropertyNames(component.prototype)
和猴子修补每个找到的方法,但经过长时间的努力,我还没有找到任何方法来提取通过分配给 class' 字段创建的函数。
我的测试堆栈由带有 Jasmine2 和 babel 的 Jest 组成。
转译的问题是arrow-function-properties(当然,正如预期的那样)分配给转译的输出实例"class"(实际上是函数, 当然)。因此,除了实例化该对象之外,我看不到任何对它们进行存根的方法,对吗? Here is the example of input es7 code and the babel's output. 但是我不是特别喜欢这个解决方案,看起来很老套。此解决方案的另一个缺点是我无法直接实例化组件的 class.
(*) 这个问题的背景是单元测试用 es7-like classes 编写的 React 组件,箭头函数分配给 class' 属性以实现自动绑定。
我在为我正在工作的项目编写单元测试时遇到了同样的问题,我认为我找到了一个很好的模式来解决它。希望对您有所帮助:
上下文
这里是一个 React 组件的例子,它有一个使用粗箭头符号定义的方法 handleClick
。
import React, { Component } from 'react';
class Foo extends Component {
componentWillMount() {
this.handleClick();
}
handleClick = (evt) => {
// code to handle click event...
}
render() {
return (
<a href="#" onClick={this.handleClick}>some foo link</a>
);
}
}
问题
如本文所述link Babel 将转译代码,以便 handleClick
方法仅在实例化后可用(检查生成的构造函数的第31到33行)
这里的问题是有时您需要在实例化 class.
之前访问使用粗箭头表示法定义的方法 例如,假设您正在为 componentWillMount
class 方法编写单元测试,并且您想要对 handleClick
进行存根,以便您只测试所需的单元。但是现在你有一个问题,因为你只能在实例化后访问 handleClick
并且 componentWillMount
方法将作为其实例化生命周期的一部分由 React
自动调用。
解决方案
以下是我如何应用一个简单的模式来解决这样的问题:
import React from 'react';
import { mount } from 'enzyme';
import { expect } from 'chai';
import sinon from 'sinon';
import Foo from './foo';
describe('Foo', () => {
describe('componentWillMount method', () => {
const handleClickStub = sinon.stub();
class FooWrapper extends Foo {
constructor(props) {
super(props);
this.handleClick = handleClickStub;
}
}
it('should register a click event listener to the externalElement property', () => {
handleClickStub.reset();
mount(<FooWrapper />);
expect(handleClickStub.calledOnce).to.be.true;
});
});
});
说明
我已将原始 Foo
组件包装到 FooWrapper
中,在初始化原始组件后,在其构造函数中,我将原始 handleClick
方法替换为存根版本,这样我就可以属性 测试我的 componentWillMount
class.
由于 babel 通过 transform-class-properties 在 class 方法上转换箭头函数语法的方式,class 方法不再绑定在原型上,而是绑定在实例上。
使用 Jest 19 的内置断言和 .spyOn 方法,这是我的解决方案:
import React from 'react';
import { shallow } from 'enzyme';
describe('MyComponent', () => {
it('should spy properly', () => {
const wrapper = shallow(<Component />);
const wrapperInstance = wrapper.instance();
const spy = jest.spyOn(wrapperInstance, 'functionName');
wrapperInstance.functionName();
expect(spy).toHaveBeenCalledTimes(1);
})
});