Экземпляр класса не может быть передан в функцию, содержащую Jasmine description- и it-blocks - PullRequest
0 голосов
/ 02 июля 2019

Хорошо, мои настройки немного запутаны, но ошибка, которую я получаю, все еще интересна.

У меня есть набор тестов Jasmine для webdriverio testrunner, который содержит функцию, объявленную в другом месте, в которую я передаю экземпляручебный класс.Эта функция, в свою очередь, содержит больше вложенных блоков описания и 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> 

Это так, как задумано, и если да, Как я могу передать экземпляр класса в функцию, которая имеет описание - и это - блоки ?Или я что-то упустил?

1 Ответ

1 голос
/ 02 июля 2019

Проблема в том, что при вызове passObject(myFunction, myObjectInstance); выполняется немедленно до того, как переменной myObjectInstance будет присвоено значение.Поэтому, когда код внутри passObject выполняется, он использует obj как undefined для каждого теста, поскольку именно это было передано в то время.

Вместо этого вы можете сделать что-то другое и передать заводская функция для вашей тестовой функции.Это позволит вам обмениваться кодом между основными тестами и тестами в 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;
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...