Почему вложенные блоки описания() не видят vars, определенные во внешних блоках?
Я столкнулся с этой проблемой в реальном коде, но я собрал тривиальный пример, чтобы доказать эту точку.
Нижеприведенный код работает нормально. Я установил переменную в моем корневом блоке describe()
, который доступен в моих блоках sub describe()
s '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();
});
});
});
http://jsfiddle.net/w5bzrkh9/
Однако, если я попытаюсь немного ПОЛУЧИТЬ мой код, выполнив следующее, он сломается:
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();
});
});
});
http://jsfiddle.net/goqcev42/
В пределах вложенной области describe()
объект orchard
имеет значение undefined, хотя он определен внутри блоков 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();
});
});
});
Ответы
Ответ 1
Это точно так, как ожидалось. Проблема в том, что ваша переменная var trees
пытается получить доступ к orchard
до ее инициализации. Тело блока описания выполняется перед блоками beforeEach
. Чтобы решить эту проблему, третий фрагмент кода - единственный способ пойти.
Жасмин сначала выполнит описывающие блоки, а затем выполнит блокировку beforeEach перед запуском каждого теста.
Ответ 2
Ну, вы все равно можете инициализировать переменные вне блока beforeEach. Я обычно делаю это для констант и все еще остаюсь СУХОЙ без введения перед каждым блоком.
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();
});
});
});
Ответ 3
Давайте рассмотрим третий фрагмент кода. Кроме того, он может быть реорганизован следующим образом:
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();
});
});
});
Для новых отправителей Жасмин, вот как вы интрепретируете вышеуказанный код:\
-
describe
определяет a test suite
. Имя test suite
здесь представляет собой пользовательскую простую строку, например "простой объект".
- A
test suite
может сам содержать другой test suites
, то есть describe
может содержать вложенные пакеты.
- Как и другие языки программирования,
orchid
является глобальным для всех функций и наборов, определенных в тестовом наборе simple object
.
Блок -
It
называется specification
или SPEC
. Блоки It
содержат отдельные тесты.
- Просто, когда
Jasmine
выполняет тестовые примеры, он сначала посещает блоки It
, означая, что он пройдет все объявления блока It
.
- Когда
Jasmine
на самом деле выполняет тестовые примеры, он будет проверять функцию beforeEach
и, следовательно, orchard
получает trees
значение, назначенное ему.
-
И, следовательно, вам не нужно писать функцию beforeEach, внутри sub suite
. Вы можете просто игнорировать
beforeEach (function() {trees = orchard.trees;});
-
Теперь сравните последний фрагмент ниже с третьим фрагментом выше.