Javascript 单元测试中的可变范围问题
我对react组件的测试如下所示(基于): 并将Javascript 单元测试中的可变范围问题,javascript,unit-testing,reactjs,enzyme,Javascript,Unit Testing,Reactjs,Enzyme,我对react组件的测试如下所示(基于): 并将组件()函数替换为: // MyComponent.test.js // Cleaner problematic part const component = () => getMountedComponent(MyComponent, props, mountedComponent); 然后该测试失败,因为component()第二次返回一个新组件,状态为null 这似乎是一个范围问题,但我无法理解这一点。 Javascript总是按值
组件()
函数替换为:
// MyComponent.test.js
// Cleaner problematic part
const component = () => getMountedComponent(MyComponent, props, mountedComponent);
然后该测试失败,因为component()第二次返回一个新组件,状态为null
这似乎是一个范围问题,但我无法理解这一点。
Javascript总是按值传递,但当变量引用
对象(包括数组),“值”是对该对象的引用
当您将getMountedComponent
函数置于外部时,您不再在description
函数中设置mountedComponent
变量,因此它将保留为未定义的
,因此它将每次创建mountedComponent
的新副本
const getMountedComponent = (MyComponent, props, mountedComponent) => {
if (!mountedComponent) {
// You are not changing the "mountedComponent" defined in your "describe" here
// because "mountedComponent" is pass by value
mountedComponent = mount(<MyComponent {...props} />);
}
return mountedComponent;
};
describe('<MyComponent />', () => {
let props;
let state;
let mountedComponent; // This stays undefined
// ...
}
const getMountedComponent=(MyComponent,props,mountedComponent)=>{
如果(!mountedComponent){
//您没有更改此处“描述”中定义的“mountedComponent”
//因为“mountedComponent”是按值传递的
mountedComponent=mount();
}
返回安装组件;
};
描述(“”,()=>{
让道具;
让国家;
let mountedComponent;//这将保持未定义状态
// ...
}
问题在于getMountedComponent
函数接受mountedComponent
参数-实际上它在该函数中创建了新的mountedComponent
变量,因此它会覆盖describle
块中定义的同名变量。因此每次调用getMountedComponent
>它会创建新的局部变量,因此您不会将任何值赋给descripe
范围中定义的mountedComponent
变量。要修复此问题,您可以在函数本身(函数在JS中是一级对象)上缓存组件,而不用使用外部变量:
function getMountedComponent(MyComponent, props) {
if (!getMountedComponent.mountedComponent) {
// Appears not to properly reassign mountedComponent
getMountedComponent.mountedComponent = mount(<MyComponent {...props} />);
}
return getMountedComponent.mountedComponent;
};
我将函数从descripe函数中拉出的原因是,它实际上比我解释的要复杂一些。这意味着我希望
getMountedComponent
存在于另一个文件中。很漂亮!它工作了:)我立即用它编写了一个函数:getMountedComponent.reset=()=>{删除getMountedComponent.mountedComponent;}
Great:)是的,添加一个清除缓存的方法是一个非常好的主意:)我之所以使用mountedComponent
,是为了能够在每次之前在中重置它,因为我实际上在这里运行了很多测试。同意,对于单个测试来说,它是没有用的。因为mountedComponent最终引用了React组件,这是一个object,如果您再次调用该函数,我希望它通过引用传递,这是错误的吗?@FlorianBienefelt我明白了,我将删除答案的这一部分。不过,最初,您的变量不是对象,因此它将保持未定义状态。即使使用对象,您也只能修改其属性,因此您不能将其作为某个新组件进行分配。@FlorianBienefelt忽略“最初,您的变量不是对象,因此它将保持未定义状态。”。即使使用对象,也会将引用的值传递给函数。因此,如果执行mountedComponent=foo
,则不会更改该引用中的内容,而只是替换了引用的值。这有点难以解释…我希望我讲得有点道理。
const getMountedComponent = (MyComponent, props, mountedComponent) => {
if (!mountedComponent) {
// You are not changing the "mountedComponent" defined in your "describe" here
// because "mountedComponent" is pass by value
mountedComponent = mount(<MyComponent {...props} />);
}
return mountedComponent;
};
describe('<MyComponent />', () => {
let props;
let state;
let mountedComponent; // This stays undefined
// ...
}
function getMountedComponent(MyComponent, props) {
if (!getMountedComponent.mountedComponent) {
// Appears not to properly reassign mountedComponent
getMountedComponent.mountedComponent = mount(<MyComponent {...props} />);
}
return getMountedComponent.mountedComponent;
};
delete getMountedComponent.mountedComponent;