Какова цель функции Mocha before()?

В Mocha есть несколько "крючков" для запуска вспомогательных функций в тесте отдельно от самих тестовых случаев (очистка баз данных, создание файлов-макетов и т.д.).

Однако, в случае before() ( не beforeEach(), тот, который я получаю), он кажется довольно избыточным.

before() запускает логику один раз перед всеми тестами в текущем пакете, поэтому зачем мне даже переносить ее в функцию?

Нет различий между двумя следующими:

describe('Something', function() {
    before(doSomePreTestLogic);
    //Tests ahoy
});

и

describe('Something', function() {
    doSomePreTestLogic();
    //Tests ahoy
});

Какой смысл обертывать мою тестовую логику с помощью before()?

Ответы

Ответ 1

Есть несколько разных причин, по которым вы можете выбрать крючок before() в своих тестах:

Семантика

Это, наверное, самый большой. Иногда вам может потребоваться выполнить задачу, например, заполнить некоторые фиктивные данные в вашей базе данных, прежде чем запускать фактический тест. Конечно, вы можете это сделать в самом тесте, но это отбрасывает вашу отчетность, если вы сталкиваетесь с ошибкой во время предварительного заполнения и перед запуском фактического тестового примера. Имея крючок before(), у вас есть логическое, семантически допустимое место для вставки такого типа логики.

Очиститель для асинхронных тестов

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

Совместимость с другими крючками:

Mocha также предоставляет несколько других крючков, а именно: after(), beforeEach() и afterEach(). Вероятно, вы могли бы задать этот же вопрос и обо всех этих других крючках, но если вы поймете, что у любого из них есть обоснованное существование, то before() действительно нужно включить для округления API.

Ответ 2

Upshot

Поместите прямо внутри кода обратного вызова describe, который будет создавать набор тестов. Я говорю о вызовах it, а также о функциях, которые могут циклически перебирать таблицы или файлы, чтобы объявить кучу тестов (вызывая it в цикле).

Поместите внутри крючки код, который фактически инициализирует состояние, на которое зависят тесты.

Все остальные соображения довольно вторичны.

Позвольте мне объяснить...

Фон

Mocha выполняет тестовый набор в две фазы:

  • Он обнаруживает, какие тесты существуют. На этом этапе он будет немедленно выполнять обратные вызовы, переданные в describe, и записывать для будущего вызова обратные вызовы, переданные функциям, объявляющим тесты (it и тому подобное), и функции, объявляющие крючки (before, beforeEach, after и т.д.).

  • Он запускает тесты. На этом этапе будут выполняться обратные вызовы, которые были записаны ранее.

Разница

Итак, рассмотрим этот пример:

function dump () { console.log("running:", this.test.fullTitle()); }
describe("top", function () {
    before(dump);
    it("test 1", dump);
    it("test 2", dump);
    describe("level 1", function () {
        before(dump);
        it("test 1", dump);
        it("test 2", dump);
    });
});

Обратите внимание, что fullTitle дает полное имя теста, начиная с верхнего уровня describe, проходя через любой вложенный describe до it или hook, который содержит этот вызов. Запустите с репортером spec и сохраните только строки running:, вы получите:

running: top "before all" hook: dump
running: top test 1
running: top test 2
running: top level 1 "before all" hook: dump
running: top level 1 test 1
running: top level 1 test 2

Обратите внимание на порядок крючков и как каждый выполняется непосредственно перед тестами, объявленными в соответствующем обратном вызове describe.

Рассмотрим этот набор:

function dump () { console.log("running:", this.test.fullTitle()); }
function directDump() { console.log("running (direct):", this.fullTitle()); }
describe("top", function () {
    directDump.call(this);
    it("test 1", dump);
    it("test 2", dump);
    describe("level 1", function () {
        directDump.call(this);
        it("test 1", dump);
        it("test 2", dump);
    });
});

Запустите с репортером spec и сохраните только строки running:, вы получите:

running (direct): top
running (direct): top level 1
running: top test 1
running: top test 2
running: top level 1 test 1
running: top level 1 test 2

Обратите внимание, что оба вызова directDump выполняются раньше всего.

Последствия

  • Если какой-либо код инициализации, который вы помещаете непосредственно внутри обратного вызова на describe, терпит неудачу, весь пробег завершается с ошибкой. Никакой тест не будет выполнен. Конец истории.

  • Если какой-либо код инициализации, который вы помещаете внутри крюка before, терпит неудачу, последствия содержатся.. С одной стороны, поскольку крюк before запускается в данный момент необходимо, есть возможность запуска любых тестов, которые запланированы ранее. Кроме того, Mocha будет пропускать те тесты, которые зависят от крюка before. Например, допустим, что этот набор:

    function dump () { console.log("running:", this.test.fullTitle()); }
    describe("top", function () {
        before(dump);
        it("test 1", dump);
        it("test 2", dump);
        describe("level 1", function () {
            before(function () { throw new Error("foo"); });
            it("test 1", dump);
            it("test 2", dump);
        });
    
        describe("level 1 (second)", function () {
            before(dump);
            it("test 1", dump);
            it("test 2", dump);
        });
    });
    

    Если вы запустите его с репортером spec, весь вывод (минус трассировка стека) будет выглядеть примерно так:

      top
    running: top "before all" hook: dump
    running: top test 1
        ✓ test 1
    running: top test 2
        ✓ test 2
        level 1
          1) "before all" hook
        level 1 (second)
    running: top level 1 (second) "before all" hook: dump
    running: top level 1 (second) test 1
          ✓ test 1
    running: top level 1 (second) test 2
          ✓ test 2
    
    
      4 passing (5ms)
      1 failing
    
      1) top level 1 "before all" hook:
         Error: foo
         [stack trace]
    

    Обратите внимание, как: а) некоторые тесты выполнялись до неудачного крючка и б) Mocha все еще выполнял тесты, которые не зависят от крючков.

Ответ 3

Семантика, как на машинах, так и на человеческом уровне.

Кроме того, он поддерживает тестовый код в соответствии с интерфейсом "экспорт", например,

module.exports = {
  before: function(){
    // ...
  },

  'Array': {
    '#indexOf()': {
      'should return -1 when not present': function(){
        [1,2,3].indexOf(4).should.equal(-1);
      }
    }
  }
};