首页 > 解决方案 > 类实例不能传递给包含 Jasmine describe- 和 it-blocks 的函数

问题描述

好的,我的设置有点复杂,但我得到的错误仍然很有趣。

我有一个用于 webdriverio 测试运行程序的 Jasmine 测试套件,其中包含一个在其他地方声明的函数,我将一个类的实例传递给该函数。该函数又包含更多嵌套的 describe- 和 it- 块。

const MyObject = require('./my-object');
const { passObject, myFunction } = require('./obj-fns');

var myObjectInstance;

describe("testing passing objects as parameters", function() {
    beforeAll(function() {
        myObjectInstance = new MyObject();
    });

    it("for a class instance inside describe/it block directly", function() {
        browser.pause(250);
        expect(myObjectInstance).not.toBe(undefined);
        expect(myObjectInstance.selector).toBe("object-class-instance");
    });

    it("for a function inside describe/it block directly", function() {
        browser.pause(250);
        expect(myFunction).not.toBe(undefined);
        expect(myFunction().selector).toBe("object-function");
    });

    passObject(myFunction, myObjectInstance);

});

my-object.js

class MyObject {
    constructor() {
        this.selector = "object-class-instance";
    }
}

module.exports = MyObject;

obj-fns.js

module.exports.passObject = function(fn, obj) {
    describe("inside a function that has a describe block", function() {

        it("and an it block for a class instance", function() {
            browser.pause(250);
            expect(obj).not.toBe(undefined);
            expect(obj.selector).toBe("object-class-instance");
        });

        it("and an it block for a function", function() {
            browser.pause(250);
            expect(fn).not.toBe(undefined);
            expect(fn().selector).toBe("object-function");
        })

    });
}

module.exports.myFunction = function() {
    return {
        selector: "object-function"
    }
}

除了检查对象(通过的类实例)是否未定义的函数it内的块之外,所有测试都通过。passObject

pass: testing passing objects as parameters for a class instance inside describe/it block directly
pass: testing passing objects as parameters for a function inside describe/it block directly
pass: testing passing objects as parameters inside a function that has a describe block and an it block for a function

fail: testing passing objects as parameters inside a function that has a describe block and an it block for a class instance (chrome_undefinedVersion with 0-0 runner)
Error: Expected undefined not to be undefined.
    at <Jasmine>
    at UserContext.<anonymous> (C:\dev\eclipse-workspace\FrontendTesting\Daimler.Van.SPP.Dashboard.Web.FrontendTesting\spec\obj-fns.js:6:29)
    at <Jasmine> 

这是否符合设计,如果是,我如何将类实例传递给具有 describe- 和 it-blocks 的函数?还是我错过了什么?

标签: javascriptjasmine

解决方案


问题是当你调用它时,它会在变量被赋值之前立即passObject(myFunction, myObjectInstance);执行。因此,当内部代码运行时,它会为每个测试使用as ,因为那是当时传入的内容。myObjectInstancepassObjectobjundefined

您可以改为做一些不同的事情并将工厂函数传递给您的测试函数。这将允许您在主要测试和其中的测试之间共享代码,passObject同时仍然允许您灵活地passObject使用不同的对象运行。

下面是代码的样子:

module.exports.passObject = function(fn, createObj) {
    describe("inside a function that has a describe block", function() {
        beforeAll(function() {
            this.obj = createObj();
        });

        it("and an it block for a class instance", function() {
            browser.pause(250);
            expect(this.obj).not.toBe(undefined);
            expect(this.obj.selector).toBe("object-class-instance");
        });

        it("and an it block for a function", function() {
            browser.pause(250);
            expect(fn).not.toBe(undefined);
            expect(fn().selector).toBe("object-function");
        })

    });
}

passObject现在采用创建obj而不是仅采用obj. 它还使用this上下文将该对象传递给测试。

使用它时,您需要提取对象的初始化并在两个地方重用它:

function createInstance { return new MyObject(); }

describe("testing passing objects as parameters", function() {
    beforeAll(function() {
        myObjectInstance = createInstance()
    });

    it("for a class instance inside describe/it block directly", function() {
        browser.pause(250);
        expect(myObjectInstance).not.toBe(undefined);
        expect(myObjectInstance.selector).toBe("object-class-instance");
    });

    it("for a function inside describe/it block directly", function() {
        browser.pause(250);
        expect(myFunction).not.toBe(undefined);
        expect(myFunction().selector).toBe("object-function");
    });

    passObject(myFunction, createInstance);

});

这会导致轻微的代码重复,因为在这两种情况下都会beforeAll调用一个函数,将结果分配给一个变量并在测试中重新使用该变量。这很好,因为变量在两种情况下都不同,因此不同的测试不必将其称为相同的东西。但是,如果您想冒稍微混淆代码的风险,您甚至可以消除这种重复。

首先,将整个beforeAll代码提取到一个

function setup() {
  this.instance = new MyObject();
}

然后你可以beforeAll直接在你的

// in the main tests
beforeAll(setup)
module.exports.passObject = function(fn, setupFn) {
    describe("inside a function that has a describe block", function() {
        beforeAll(setupFn);
        /* ...tests...*/
   }
}

但是,这意味着两个测试必须引用相同的东西:this.instance并且目前还不清楚应该或将在this测试的上下文中初始化什么。此外,一组测试可能需要初始化更多的东西,而另一组则更少,例如,一个可能只使用this.instance另一个可能还需要this.foo

因此,如果您选择这条路线,则必须检查测试范围,以免设置功能不断增长以适应每个可能的属性。

此外,如果您想为同一事物使用不同的名称,那么您仍然可以只拥有两个指向相同值的属性。这将减轻两组测试的一些强加样式。例如:

function setup() {
  //for the main tests
  this.myObjectInstance = new MyObject();

  //for `passObject` just alias the same thing:
  this.obj = this.myObjectInstance;
}

推荐阅读