在mocha中通过引用将变量传递给外部测试



我知道,对于基元数据类型,通过引用传递在javascript中不起作用,所以解决方法是将它们封装在对象中。但是考虑一个场景,其中变量的初始状态为null,然后将变量重新分配为Object。现在,如果该变量作为参数传递给外部函数,它将作为引用传递,还是最终在函数内成为undefined

为了参考,考虑这个用例:

登录端点的摩卡测试中

方法1

describe('Login Endpoint Test', function(){
let response = null;

before('test pre-requisites', async function(){
this.timeout(15000);
response = await endpointCall(); //returns response Object
});   
it('simple endpoint test', function(){
//response is availble here.
response.should.have.status(200);
});

/*Importing an external testfile.*/
require('./externalTest.spec.js')(response);
})

在externalTest.spec.js 中

module.exports = (response) => {
it('external test', function(){
console.log(response);  // null;
})
}

如果我将响应封装在Object中,它就可以工作了。为什么会这样?

方法2

如果我将响应封装在Object中,它就可以工作了。为什么会这样?

describe('Login Endpoint Test', function(){
let data = {response: null};

before('test pre-requisites', async function(){
this.timeout(15000);
data.response = await endpointCall(); //returns response Object
});   
it('simple endpoint test', function(){
//response is availble here.
data.response.should.have.status(200);
});

/*Importing an external testfile.*/
require('./externalTest.spec.js')(data);
})

在externalTest.spec.js 中

module.exports = (data) => {
it('external test', function(){
console.log(data.response);  // response object;
})
}

注意:如果您发现不清楚,请告诉我。提前谢谢

我能做的最直接的比较是PHP,它在这方面与Javascript有一些非常巨大的差异。

首先,在PHP中,如果将数组传递给函数,并更改函数中的数组,则原始数组实际上不会更改。如果您传入以下值,数组将被完全复制:

$arr = [];
func($arr);
var_dump($arr);
function func($arr) {
$arr['key'] = 'value';
}

当您在PHP中使用var_dump($arr)时,您可能希望它具有'key' => 'value',但在PHP中情况并非如此。

javascript中的相同示例如下:

let obj = {};
func(obj);
console.log(obj);
function func(obj) {
obj['key'] = 'value';
}

您可以看到,与PHP的数组示例不同,在Javascript中直接更改对象在两个位置都会更改对象。

这就给我们带来了下一个巨大的区别——PHP有一个完整的引用传递功能,比如:

$arr = [];
func($arr);
var_dump($arr);
function func(&$arr) {
$arr['key'] = 'value';
}

PHP中的&符号表示通过引用,因此在PHP中的该示例中,当您使用var_dump($arr)时,您将看到key => value

然而,这个&符号实际上并没有使PHP使用该变量的行为与Javascript的行为相同。因为在PHP中,它是通过引用传递的TRUE,所以可以这样做:

$arr = [];
func($arr);
var_dump($arr);
function func(&$arr) {
$arr = 2;
}

所以当你var_dump($arr)时,它会输出2,因为func实际上改变了$arr在基本层面上的含义。

与Javascript相比,func函数不能改变obj的实际含义,它所能做的就是改变你发送的内容

let obj = {};
func(obj);
console.log(obj);
function func(obj) {
obj = 2;
}

那么当你console.log(obj)时,你仍然会得到你开始使用的空对象。func不能通过使用=符号来改变外界认为obj指的是什么。

实际上,我想我对它的工作原理有一些想法。

为什么方法#1失败

当需要并调用外部函数时,我们会将响应变量传递给它。该响应变量当前的值为nullbefore函数将响应变量重新分配给一个新的响应对象,它实际上不会在导出函数执行上下文中更新,因为null标量基元值之一(Number、String、Boolean、undefined、null、Symbol)。对于标量基元值,javascript使用stack内存结构,每次重新分配时,我们都会在堆栈顶部添加一个新值,变量就会指向它。因此,导出的函数不知道推送到堆栈的新值,而只知道对旧值的引用。

为什么方法#2成功

现在,当我们将响应包装为对象时,我们实际上使用了两种内存结构,一种是堆栈,另一种是堆。响应的原始值存储在堆中,并在堆栈中维护对它的引用。因此,当before函数更新数据对象的键(响应)时,它实际上不会在堆栈顶部推送一个新值,而是在堆中更新,否则将保持相同的引用。因此,当导出函数内的it执行时,它可以找到原始数据。

希望这能有所帮助。

我已经运行了您的代码,问题很直接。我将用哪些行首先运行来注释它,以便您查看事件的顺序

1 describe('Login Endpoint Test', function(){ 
2 let data = null;

3 before('test pre-requisites', async function(){
8 this.timeout(15000);
9 data.response = await endpointCall(); //returns response Object
});   
4 it('simple endpoint test', function(){
//response is availble here.
10 data.response.should.have.status(200);
});

/*Importing an external testfile.*/
5 require('./externalTest.spec.js')(data);
})
// different file
6 module.exports = (data) => {
7 it('external test', function(){
11 console.log(data.response);
})
}

这里的重要比特是(2)和(5)。你说的是data is null,然后是require expternalTest.spec.js and pass it whatever data is (which is null)

因此,永远测试.spec.js只会立即以null的形式获取数据,而且它永远不会也不可能有其他数据。你已经通过了null,就这样,就是这样。

在第二个方法中,执行顺序完全相同,但您没有将其传递为null,而是将其传递给了对象。当然,随着对象的变化(response属性得到一个值),expternalTest.spec.js所看到的data也会变化,因为data就是那个对象!

相关内容

  • 没有找到相关文章

最新更新