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

时间:2015-02-16 16:39:03

标签: javascript jasmine

我在实际代码中遇到过这个问题,但我总结了一个简单的例子来证明这一点。

以下代码运行正常。我在我的根describe()块中设置了一个变量,可以在我的子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对象未定义,即使它在其中的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();
        });
    });
});

3 个答案:

答案 0 :(得分:42)

这完全符合预期。问题是您的var trees变量在初始化之前尝试访问orchard。描述块的主体在beforeEach块之前执行。要解决此问题,第三个代码段是唯一的方法。

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

答案 1 :(得分:1)

那么你仍然可以在beforeEach块之外初始化变量。我通常是为常数做的,并且仍然保持DRY而不引入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();
        });
    });
});

答案 2 :(得分:0)

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

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 的新人,这就是你如何代表上述代码:\

  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值。< / LI>
  7. 因此您无需在sub suite内编写beforeEach 函数。你可以忽略

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

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