我目前正在尝试对React组件进行单元测试,并且在帮助函数模拟函数方面遇到了一些困惑。该模块看起来像这样
export const someHelper = () => {
return ( <div></div> )
}
const MyComponent = () => {
return (
<span>
{someHelper()}
</span>
)
}
export default MyComponent
然后这就是测试文件的样子
import chai, { expect } from 'chai'
import chaiEnzyme from 'chai-enzyme'
import sinon from 'sinon'
import { shallow } from 'enzyme'
import React from 'react'
import MyComponent, { someHelper } from './MyComponent'
describe('MyComponent test', function (){
it.only('should call someHelper once', function () {
let spy = sinon.spy(someHelper)
let myComponent = shallow(
<MyComponent />
)
expect(spy.callCount).to.equal(1)
})
})
然而,当callCount等于0时,此测试失败。我认为它可能与someHelper
函数的上下文有关,所以我做了这些更改
export const helpers = {
someHelper () {
...
}
}
const MyComponent = () => {
...
{helpers.someHelper()}
...
}
_
import MyComponent, { helpers } ...
describe(...{
it(...{
let spy = sinon.spy(helpers.someHelper)
...
})
})
但是这个测试仍然失败,callCount等于0.然后我做了这些修改
describe(...{
it(...{
let spy = sinon.spy(helpers, 'someHelper')
...
})
})
然后测试现在通过。
为什么我必须将someHelper
附加到helpers
对象才能使此测试生效?当sinon docs显示spy(object, 'myfunc')
选项时,为什么必须使用上一个spy(myFunc)
方法?
答案 0 :(得分:3)
为什么我必须将
someHelper
附加到helpers
对象才能使此测试生效?
Sinon必须能够使用spy / stub-wrapped版本替换对现有函数的引用,并且只有当该引用存储在对象中时才能这样做(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 docs显示
spy(myFunc)
选项时?
我发现这个成语通常用途有限。正如您所想,它不会监视对myFunc
的所有调用,除非对spy()
的结果发出间谍对象的调用。
例如:
let callback = (err, result) => { ... }
...
let spy = sinon.spy(callback);
someFuncToTest(spy);
expect(spy.callCount).to.equal(1);
因此,不是直接传递回调函数,而是传递间谍。
答案 1 :(得分:1)
问题不是针对React或Sinon而是针对JS的。
如果发生类似的事情
var spiedMethod = (...args) => {
console.log('spy!');
return object.method(...args);
};
这会创建一个不替换原始object
方法的新函数。如果调用object.method
,则不会调用spiedMethod
- 原始方法将被调用。要在object
上替换它,应修改对象:
object.method = spiedMethod;
这正是Sinon间谍所做的事情。
let spy = sinon.spy(myFunc);
为提供的函数返回sinon.spy(myFunc)
间谍。为了对来电进行监视,应调用spy
而不是myFunc
。
除非这样的事情已经完成
helpers.someHelper = sinon.spy(helpers.someHelper);
Sinon无法将spy
函数与spied方法联系起来。这是
sinon.spy(helpers, 'someHelper')
来救援。它本质上是helpers.someHelper = spy
,但也会在内部保存原始方法,因此在调用helpers.someHelper = someHelperOriginal
时它可以helpers.someHelper.restore()
。