为什么嵌套的 describe() 块看不到外部块中定义的变量?
Why can't nested describe() blocks see vars defined in outer blocks?
我已经 运行 在实际代码中解决了这个问题,但我举了一个简单的例子来证明这一点。
下面的代码工作正常。我在我的根 describe()
块中设置了一个变量,可以在我的子 describe()
的 it()
块中访问。
describe('simple object', function () {
var orchard;
beforeEach(function () {
orchard = {
trees: {
apple: 10,
orange : 20
},
bushes: {
boysenberry : 40,
blueberry: 35
}
};
});
describe('trees', function () {
it ('should have apples and oranges', function() {
var trees = orchard.trees;
expect (trees.apple).toBeDefined();
expect (trees.orange).toBeDefined();
expect (trees.apple).toEqual(10);
expect (trees.orange).toEqual(20);
});
it ('should NOT have pears or cherries', function() {
var trees = orchard.trees;
expect (trees.pear).toBeUndefined();
expect (trees.cherry).toBeUndefined();
});
});
});
但是,如果我尝试通过执行以下操作稍微干燥我的代码,它就会中断:
describe('simple object', function () {
var orchard;
beforeEach(function () {
orchard = {
trees: {
apple: 10,
orange : 20
},
bushes: {
boysenberry : 40,
blueberry: 35
}
};
});
describe('trees', function () {
var trees = orchard.trees; // TypeError: Cannot read property 'trees' of undefined
it ('should have apples and oranges', function() {
expect (trees.apple).toBeDefined();
expect (trees.orange).toBeDefined();
expect (trees.apple).toEqual(10);
expect (trees.orange).toEqual(20);
});
it ('should NOT have pears or cherries', function() {
expect (trees.pear).toBeUndefined();
expect (trees.cherry).toBeUndefined();
});
});
});
在嵌套的 describe()
范围内,orchard
对象未定义,即使它是在其中的 it()
块中定义的。
Jasmine 的开发人员是否有意这样做,可能是为了避免在 beforeEach()
中重置对象并可能破坏某些引用的问题?他们如何做到这一点?我可以看到这可能有什么用,我只是很好奇它是如何工作的。 (我的猜测是一些 apply()
或 call()
魔法,但我不确定如何...)
--
作为旁注,我仍然可以通过简单地使用另一个 beforeEach()
块来干燥我的代码:
describe('simple object', function () {
var orchard;
beforeEach(function () {
orchard = {
trees: {
apple: 10,
orange : 20
},
bushes: {
boysenberry : 40,
blueberry: 35
}
};
});
describe('trees', function () {
var trees;
beforeEach(function() {
trees = orchard.trees;
});
it ('should have apples and oranges', function() {
expect (trees.apple).toBeDefined();
expect (trees.orange).toBeDefined();
expect (trees.apple).toEqual(10);
expect (trees.orange).toEqual(20);
});
it ('should NOT have pears or cherries', function() {
expect (trees.pear).toBeUndefined();
expect (trees.cherry).toBeUndefined();
});
});
});
describe
块的主体在 beforeEach
块之前执行。
这完全符合预期。问题是您的 var trees
变量在初始化之前试图访问 orchard
。 describe
块的主体在 beforeEach
块之前执行。 要解决此问题,第三个代码片段是唯一的方法。
Jasmine 将首先执行 describe 块,然后在 运行 每次测试之前执行 beforeEach 块。
好吧,您仍然可以在 beforeEach 块之外初始化变量。我通常对常量执行此操作,并且在不引入 beforeEach 块的情况下仍然保持 DRY。
describe('simple object', function () {
const orchard = {
trees: {
apple: 10,
orange: 20
},
bushes: {
boysenberry: 40,
blueberry: 35
}
};
describe('trees', function () {
const trees = orchard.trees;
it('should have apples and oranges', function () {
expect(trees.apple).toBeDefined();
expect(trees.orange).toBeDefined();
expect(trees.apple).toEqual(10);
expect(trees.orange).toEqual(20);
});
it('should NOT have pears or cherries', function () {
var trees = orchard.trees;
expect(trees.pear).toBeUndefined();
expect(trees.cherry).toBeUndefined();
});
});
});
让我们来看第三个代码片段。此外,它可以重构如下:
describe('simple object', function () {
var orchard;
beforeEach(function () {
orchard = {
trees: {
apple: 10,
orange : 20
},
bushes: {
boysenberry : 40,
blueberry: 35
}
};
});
describe('trees', function () {
it ('should have apples and oranges', function() {
expect (orchard.trees.apple).toBeDefined();
expect (orchard.trees.orange).toBeDefined();
expect (orchard.trees.apple).toEqual(10);
expect (orchard.trees.orange).toEqual(20);
});
it ('should NOT have pears or cherries', function() {
expect (orchard.trees.pear).toBeUndefined();
expect (orchard.trees.cherry).toBeUndefined();
});
});
});
对于 Jasmine 的新手,这就是你如何解释上面的代码:\
describe
定义了一个test suite
。这里的 test suite
名称是用户定义的简单字符串,例如 "simple object".
- A
test suite
本身可以包含其他 test suites
,这意味着 describe
可以包含嵌套套件。
- 就像其他编程语言一样,
orchid
对于 simple object
测试套件中定义的所有函数和套件是全局的。
It
块称为 specification
或 SPEC
。 It
个块包含单独的测试。
- 当
Jasmine
执行测试用例时,它将首先访问it
块,这意味着它将遍历所有it
块声明。
- 当
Jasmine
实际上执行测试用例时,它将检查beforeEach
函数,因此orchard
得到trees
值分配给它。
因此你不需要在sub suite
里面写一个beforeEach函数。你可以简单地忽略
beforeEach (function() { trees = orchard.trees; });
现在将下面的最新代码段与上面的第三个代码段进行比较。
我已经 运行 在实际代码中解决了这个问题,但我举了一个简单的例子来证明这一点。
下面的代码工作正常。我在我的根 describe()
块中设置了一个变量,可以在我的子 describe()
的 it()
块中访问。
describe('simple object', function () {
var orchard;
beforeEach(function () {
orchard = {
trees: {
apple: 10,
orange : 20
},
bushes: {
boysenberry : 40,
blueberry: 35
}
};
});
describe('trees', function () {
it ('should have apples and oranges', function() {
var trees = orchard.trees;
expect (trees.apple).toBeDefined();
expect (trees.orange).toBeDefined();
expect (trees.apple).toEqual(10);
expect (trees.orange).toEqual(20);
});
it ('should NOT have pears or cherries', function() {
var trees = orchard.trees;
expect (trees.pear).toBeUndefined();
expect (trees.cherry).toBeUndefined();
});
});
});
但是,如果我尝试通过执行以下操作稍微干燥我的代码,它就会中断:
describe('simple object', function () {
var orchard;
beforeEach(function () {
orchard = {
trees: {
apple: 10,
orange : 20
},
bushes: {
boysenberry : 40,
blueberry: 35
}
};
});
describe('trees', function () {
var trees = orchard.trees; // TypeError: Cannot read property 'trees' of undefined
it ('should have apples and oranges', function() {
expect (trees.apple).toBeDefined();
expect (trees.orange).toBeDefined();
expect (trees.apple).toEqual(10);
expect (trees.orange).toEqual(20);
});
it ('should NOT have pears or cherries', function() {
expect (trees.pear).toBeUndefined();
expect (trees.cherry).toBeUndefined();
});
});
});
在嵌套的 describe()
范围内,orchard
对象未定义,即使它是在其中的 it()
块中定义的。
Jasmine 的开发人员是否有意这样做,可能是为了避免在 beforeEach()
中重置对象并可能破坏某些引用的问题?他们如何做到这一点?我可以看到这可能有什么用,我只是很好奇它是如何工作的。 (我的猜测是一些 apply()
或 call()
魔法,但我不确定如何...)
--
作为旁注,我仍然可以通过简单地使用另一个 beforeEach()
块来干燥我的代码:
describe('simple object', function () {
var orchard;
beforeEach(function () {
orchard = {
trees: {
apple: 10,
orange : 20
},
bushes: {
boysenberry : 40,
blueberry: 35
}
};
});
describe('trees', function () {
var trees;
beforeEach(function() {
trees = orchard.trees;
});
it ('should have apples and oranges', function() {
expect (trees.apple).toBeDefined();
expect (trees.orange).toBeDefined();
expect (trees.apple).toEqual(10);
expect (trees.orange).toEqual(20);
});
it ('should NOT have pears or cherries', function() {
expect (trees.pear).toBeUndefined();
expect (trees.cherry).toBeUndefined();
});
});
});
describe
块的主体在 beforeEach
块之前执行。
这完全符合预期。问题是您的 var trees
变量在初始化之前试图访问 orchard
。 describe
块的主体在 beforeEach
块之前执行。 要解决此问题,第三个代码片段是唯一的方法。
Jasmine 将首先执行 describe 块,然后在 运行 每次测试之前执行 beforeEach 块。
好吧,您仍然可以在 beforeEach 块之外初始化变量。我通常对常量执行此操作,并且在不引入 beforeEach 块的情况下仍然保持 DRY。
describe('simple object', function () {
const orchard = {
trees: {
apple: 10,
orange: 20
},
bushes: {
boysenberry: 40,
blueberry: 35
}
};
describe('trees', function () {
const trees = orchard.trees;
it('should have apples and oranges', function () {
expect(trees.apple).toBeDefined();
expect(trees.orange).toBeDefined();
expect(trees.apple).toEqual(10);
expect(trees.orange).toEqual(20);
});
it('should NOT have pears or cherries', function () {
var trees = orchard.trees;
expect(trees.pear).toBeUndefined();
expect(trees.cherry).toBeUndefined();
});
});
});
让我们来看第三个代码片段。此外,它可以重构如下:
describe('simple object', function () {
var orchard;
beforeEach(function () {
orchard = {
trees: {
apple: 10,
orange : 20
},
bushes: {
boysenberry : 40,
blueberry: 35
}
};
});
describe('trees', function () {
it ('should have apples and oranges', function() {
expect (orchard.trees.apple).toBeDefined();
expect (orchard.trees.orange).toBeDefined();
expect (orchard.trees.apple).toEqual(10);
expect (orchard.trees.orange).toEqual(20);
});
it ('should NOT have pears or cherries', function() {
expect (orchard.trees.pear).toBeUndefined();
expect (orchard.trees.cherry).toBeUndefined();
});
});
});
对于 Jasmine 的新手,这就是你如何解释上面的代码:\
describe
定义了一个test suite
。这里的test suite
名称是用户定义的简单字符串,例如 "simple object".- A
test suite
本身可以包含其他test suites
,这意味着describe
可以包含嵌套套件。 - 就像其他编程语言一样,
orchid
对于simple object
测试套件中定义的所有函数和套件是全局的。 It
块称为specification
或SPEC
。It
个块包含单独的测试。- 当
Jasmine
执行测试用例时,它将首先访问it
块,这意味着它将遍历所有it
块声明。 - 当
Jasmine
实际上执行测试用例时,它将检查beforeEach
函数,因此orchard
得到trees
值分配给它。 因此你不需要在
sub suite
里面写一个beforeEach函数。你可以简单地忽略beforeEach (function() { trees = orchard.trees; });
现在将下面的最新代码段与上面的第三个代码段进行比较。