Подтвердить что ты не робот

Почему вложенные блоки описания() не видят 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();
        });
    });
});
4b9b3361

Ответ 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;});

  • Теперь сравните последний фрагмент ниже с третьим фрагментом выше.