为什么嵌套的 describe() 块不能看到在外部块中定义的变量

Why can't nested describe() blocks see vars defined in outer blocks?

本文关键字:外部 定义 变量 不能 describe 嵌套 为什么      更新时间:2023-12-22

我在实际代码中遇到了这个问题,但我整理了一个微不足道的例子来证明这一点。

下面的代码工作正常。我已经在我的根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();
        });
    });
});

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对象是未定义的,即使它是在其中的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变量在初始化之前正在尝试访问orcharddescribe块的主体在beforeEach块之前执行。 为了解决这个问题,第三个代码片段是唯一的方法。

Jasmine 将首先执行描述块,然后在运行每个测试之前执行 beforeEach 块。

好吧,

您仍然可以初始化 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();
        });
    });
});

让我们看第三个代码片段。此外,它可以重构如下:

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();
        });
    });
});

对于茉莉花的新人,这就是你如何理解上面的代码:''

  1. describe定义了一个test suite。这里的test suite名称是用户定义的简单字符串,比如"简单对象"。
  2. test suite本身可以包含其他test suites,这意味着describe可以包含嵌套套件。
  3. 就像其他编程语言一样,orchid 对测试套件中定义的所有函数和套件都是全局的simple object
  4. It块称为specificationSPECIt块包含单个测试。
  5. 就在Jasmine执行测试用例时,它将首先访问it块,这意味着它将遍历所有it块声明。
  6. Jasmine实际执行测试用例时,它将检查beforeEach函数,因此orchard获取分配给它trees值。
  7. 因此,您无需在sub suite编写 beforeEach 函数。你可以简单地忽略

    beforeEach (function(( { trees = orchard.trees; }(;

  8. 现在将下面的最新代码段与上面的第三个代码段进行比较。