Javascript 与使用sinon、enyzme和ES6导入模拟无状态React组件帮助器函数混淆
我目前正在尝试对React组件进行单元测试,但在模拟函数和辅助函数方面遇到了一些困惑。模块看起来像这样Javascript 与使用sinon、enyzme和ES6导入模拟无状态React组件帮助器函数混淆,javascript,testing,reactjs,ecmascript-6,sinon,Javascript,Testing,Reactjs,Ecmascript 6,Sinon,我目前正在尝试对React组件进行单元测试,但在模拟函数和辅助函数方面遇到了一些困惑。模块看起来像这样 export const someHelper = () => { return ( <div></div> ) } const MyComponent = () => { return ( <span> {someHelper()} </span> ) } export default My
export const someHelper = () => {
return ( <div></div> )
}
const MyComponent = () => {
return (
<span>
{someHelper()}
</span>
)
}
export default MyComponent
_
但是这个测试仍然失败,callCount等于0。然后我做了这些改变
export const helpers = {
someHelper () {
...
}
}
const MyComponent = () => {
...
{helpers.someHelper()}
...
}
describe(...{
it(...{
let spy = sinon.spy(helpers, 'someHelper')
...
})
})
现在测试通过了
为什么我必须将someHelper
附加到helpers
对象才能进行此测试?当显示spy(myfunc)
选项时,为什么我必须使用最后一个spy(object,'myfunc')
方法
为什么我必须将someHelper
附加到helpers
对象才能进行此测试
Sinon必须能够用spy/stub包装版本的函数替换对现有函数的引用,并且只有当引用存储在对象中时,它才能这样做(helpers
)
它基本上是这样做的:
let functionToSpyOn = helpers.someHelper;
let spy = sinon.spy(functionToSpyOn);
helpers.someHelper = spy;
这里的另一个复杂之处是,原始代码必须通过此引用调用函数,因此类似这样的操作也不起作用:
const someHelper = () => { ... }
export const helpers = { someHelper }
const MyComponent = () => {
...
{someHelper()}
...
}
原因是MyComponent
没有使用存储在helpers
中的引用,该引用正被Sinon所取代。这就是为什么组件需要使用helpers.someHelper()
为什么我必须使用最后一个spy(object,'myfunc')
方法
这同样与用包装版本的函数替换函数有关
…当sinon文档显示spy(myFunc)
选项时
我发现这个习语通常用处不大。正如您所想,它不会监视对myFunc
的所有调用,除非这些调用是对spy()的结果spy对象进行的
例如:
let callback = (err, result) => { ... }
...
let spy = sinon.spy(callback);
someFuncToTest(spy);
expect(spy.callCount).to.equal(1);
因此,不直接传递回调函数,而是传递spy
为什么我必须将someHelper
附加到helpers
对象才能进行此测试
Sinon必须能够用spy/stub包装版本的函数替换对现有函数的引用,并且只有当引用存储在对象中时,它才能这样做(helpers
)
它基本上是这样做的:
let functionToSpyOn = helpers.someHelper;
let spy = sinon.spy(functionToSpyOn);
helpers.someHelper = spy;
这里的另一个复杂之处是,原始代码必须通过此引用调用函数,因此类似这样的操作也不起作用:
const someHelper = () => { ... }
export const helpers = { someHelper }
const MyComponent = () => {
...
{someHelper()}
...
}
原因是MyComponent
没有使用存储在helpers
中的引用,该引用正被Sinon所取代。这就是为什么组件需要使用helpers.someHelper()
为什么我必须使用最后一个spy(object,'myfunc')
方法
这同样与用包装版本的函数替换函数有关
…当sinon文档显示spy(myFunc)
选项时
我发现这个习语通常用处不大。正如您所想,它不会监视对myFunc
的所有调用,除非这些调用是对spy()的结果spy对象进行的
例如:
let callback = (err, result) => { ... }
...
let spy = sinon.spy(callback);
someFuncToTest(spy);
expect(spy.callCount).to.equal(1);
因此,不直接传递回调函数,而是传递spy。问题不在于React或Sinon,而在于JS
如果发生这样的事情
var spiedMethod = (...args) => {
console.log('spy!');
return object.method(...args);
};
这将创建一个新函数,该函数不会替换原始的对象
方法。如果调用了object.method
,则不会调用spiedMethod
——将调用原始方法。要在对象
上替换它,应修改该对象:
object.method = spiedMethod;
这正是Sinon间谍所做的
let spy = sinon.spy(myFunc);
返回所提供函数的间谍。为了监视调用,应该调用spy
,而不是myFunc
除非这样做
helpers.someHelper = sinon.spy(helpers.someHelper);
Sinon无法将spy
函数与spied方法相关联。这就是
sinon.spy(helpers, 'someHelper')
来营救。它本质上是执行helpers.someHelper=spy
,但也在内部保存原始方法,因此当调用helpers.someHelper.restore()
时,它可以执行helpers.someHelper=someHelper.restore()。问题不在于React或Sinon,而在于JS
如果发生这样的事情
var spiedMethod = (...args) => {
console.log('spy!');
return object.method(...args);
};
这将创建一个新函数,该函数不会替换原始的对象
方法。如果调用了object.method
,则不会调用spiedMethod
——将调用原始方法。要在对象
上替换它,应修改该对象:
object.method = spiedMethod;
这正是Sinon间谍所做的
let spy = sinon.spy(myFunc);
返回所提供函数的间谍。为了监视调用,应该调用spy
,而不是myFunc
除非这样做
helpers.someHelper = sinon.spy(helpers.someHelper);
Sinon无法将spy
函数与spied方法相关联。这就是
sinon.spy(helpers, 'someHelper')
来营救。它基本上执行helpers.someHelper=spy
操作,但也在内部保存原始方法,因此当调用helpers.someHelper.restore()
时,它可以执行helpers.someHelper=someHelper-original
。回答得好,谢谢!那么,是否真的没有办法存根一个不是通过某个对象(即helpers)直接调用的函数?@Weston不是通过Sinon直接调用的,但可能能够帮助您解决问题(前者可能不会太多,因为它不适用于Babel)。回答得很好,谢谢!那么,是否真的没有办法存根一个直接调用的函数,而不是通过某个对象(即helpers)?@Weston没有直接使用Sinon,但可能能够帮助您解决问题(前者可能不会太多,因为它不适用于Babel)。