Какой хороший способ повторно использовать тестовый код с использованием Jasmine? - PullRequest
21 голосов
/ 21 февраля 2011

Я использую библиотеку Javascript Jasmine BDD и действительно наслаждаюсь ею.У меня есть тестовый код, который я хотел бы использовать повторно (например, для тестирования нескольких реализаций базового класса или выполнения одних и тех же тестов в несколько ином контексте), и я не уверен, как это сделать с помощью Jasmine.Я знаю, что могу переместить код из функций жасмина в классы многократного использования, но мне нравится, как код читает с вкраплениями функций жасмина (опишите его), и я не хочу отделять спецификации от тестового кода, если ядолжен.Кто-нибудь с помощью Жасмин сталкивался с этой проблемой и как вы справились с этим?

Ответы [ 7 ]

28 голосов
/ 22 июня 2011

Вот статья парня из Pivotal Labs, в которой подробно рассказывается о том, как обернуть описательный вызов:

Сушить спецификации жасмина с общим поведением

Отрывок из статьи, в которой показана часть функции оболочки:

function sharedBehaviorForGameOf(context) {
  describe("(shared)", function() {
    var ball, game;
    beforeEach(function() {
      ball = context.ball;
      game = context.game;
    });
  });
}
11 голосов
/ 21 ноября 2014

Я не уверен, как работает решение @ starmer. Как я уже упоминал в комментарии, когда я использую его код, context всегда неопределен.

Вместо этого, что вы должны сделать (как упомянуто @moefinley), вместо этого передать ссылку на функцию конструктора. Я написал сообщение в блоге , в котором описывается этот подход на примере. Вот суть этого:

describe('service interface', function(){
    function createInstance(){
        return /* code to create a new service or pass in an existing reference */
    }

    executeSharedTests(createInstance);
});

function executeSharedTests(createInstanceFn){
    describe('when adding a new menu entry', function(){
        var subjectUnderTest;

        beforeEach(function(){
            //create an instance by invoking the constructor function
            subjectUnderTest = createInstanceFn();
        });

        it('should allow to add new menu entries', function(){
            /* assertion code here, verifying subjectUnderTest works properly */
        });
    });
}
2 голосов
/ 20 марта 2015

На сайте Хотябота есть хорошая статья: https://robots.thoughtbot.com/jasmine-and-shared-examples

Вот краткий пример:

appNamespace.jasmine.sharedExamples = {
  "rectangle": function() {
    it("has four sides", function() {
      expect(this.subject.sides).toEqual(4);
    });
  },
 };

И с некоторыми функциями подчеркивания, чтобы определить itShouldBehaveLike

window.itShouldBehaveLike = function() {
  var exampleName      = _.first(arguments),
      exampleArguments = _.select(_.rest(arguments), function(arg) { return !_.isFunction(arg); }),
      innerBlock       = _.detect(arguments, function(arg) { return _.isFunction(arg); }),
      exampleGroup     = appNamespace.jasmine.sharedExamples[exampleName];

  if(exampleGroup) {
    return describe(exampleName, function() {
      exampleGroup.apply(this, exampleArguments);
      if(innerBlock) { innerBlock(); }
    });
  } else {
    return it("cannot find shared behavior: '" + exampleName + "'", function() {
      expect(false).toEqual(true);
    });
  }
};
1 голос
/ 07 апреля 2016

Это мой подход, вдохновленный этой статьей:

https://gist.github.com/traviskaufman/11131303

на основе собственной документации Жасмин:

http://jasmine.github.io/2.0/introduction.html#section-The_%3Ccode%3Ethis%3C/code%3E_keyword

Установив общие зависимости в качестве свойств прототипа функции beforeEach, вы можете расширить beforeEach, чтобы сделать эти зависимости доступными через this.

Пример:

describe('A suite', function() {
    // Shared setup for nested suites
    beforeEach(function() {
        // For the sake of simplicity this is just a string
        // but it could be anything
        this.sharedDependency = 'Some dependency';
    });

    describe('A nested suite', function() {
        var dependency;

        beforeEach(function() {
            // This works!
            dependency = this.sharedDependency;                
        });

        it('Dependency should be defined', function() {
            expect(dependency).toBeDefined();
        });
    });

    describe('Check if string split method works', function() {
        var splitToArray;

        beforeEach(function() {
            splitToArray = this.sharedDependency.split();                
        });

        it('Some other test', function() { ... });
    });
});

Я знаю, что мой пример бесполезен, но он должен служить своей цели в качестве примера кода.

Конечно, это лишь одна из многих вещей, которые вы можете сделать, чтобы добиться того, что вы говорите, я уверен, что более сложные шаблоны проектирования могут быть применены сверху или в стороне от этого.

Надеюсь, это поможет!

1 голос
/ 08 июня 2015

Это похоже на ответ стармера, но после проработки я обнаружил некоторые отличия, на которые следует обратить внимание. Недостатком является то, что в случае сбоя спецификации вы просто видите «следует придерживаться общих сохраняющих спецификаций» в отчете Jasmine. Трассировка стека - это единственный способ найти ошибку.

// common specs to execute
self.executeCommonSpecifications = function (vm) {
  // I found having the describe( wrapper here doesn't work
  self.shouldCallTheDisplayModelsSaveMethod(vm);
}
self.shouldCallTheDisplaysSaveMethod = function (vm) {
  expect(vm.save.calls.count()).toBe(1);
};

// spec add an it so that the beforeEach is called before calling this
beforeEach(function(){
  // this gets called if wrapped in the it
  vm.saveChanges();
}
it('should adhere to common saving specifications', function () {
  executeSavingDisplaysCommonSpecifications(vm);
});
0 голосов
/ 21 сентября 2018

Позвольте мне резюмировать это с рабочим примером.

  describe('test', function () {

    beforeEach(function () {
      this.shared = 1;
    });

    it('should test shared', function () {
      expect(this.shared).toBe(1);
    });

    testShared();
  });

  function testShared() {
    it('should test in function', function() {
      expect(this.shared).toBe(1);
  });

  }

Важнейшими частями здесь являются это ключевое слово для передачи контекста, и поэтому мы должны использовать "нормальные" функции (еще одна важная часть).

Для производственного кода я бы, вероятно, использовал бы обычную функцию только в beforeEach для передачи / извлечения контекста, но для краткости продолжал использовать стрелочную функцию в спецификациях.

Передача контекста в качестве параметра не будет работать, потому что обычно мы определяем контекст в блоке beforeEach, который вызывается после.

Наличие секции describe кажется не важным, но все же приветствуется лучшая структура

0 голосов
/ 12 марта 2011

Мне было указано заключить вызов описания в функцию, которая передает ему параметр.

...