2014-06-05 5 views
5

Я очень новичок в модульных тестах, mocha и should.js, и я пытаюсь написать тест для асинхронного метода, который возвращает обещание. Вот мой тестовый код:should.js не приводит к ошибке моккового теста

var should = require("should"), 
    tideRetriever = require("../tide-retriever"), 
    moment = require("moment"), 
    timeFormat = "YYYY-MM-DD-HH:mm:ss", 
    from = moment("2013-03-06T00:00:00", timeFormat), 
    to = moment("2013-03-12T23:59:00", timeFormat), 
    expectedCount = 300; 

describe("tide retriever", function() { 
    it("should retrieve and parse tide CSV data", function() { 
     tideRetriever.get(from, to).then(
      function(entries) { // resolve 
       entries.should.be.instanceof(Array).and.have.lengthOf(expectedCount); 
      }, 
      function(err) { // reject 
       should.fail("Promise rejected", err); 
      } 
     ); 
    }); 
}); 

Когда я вручную проверить метод tideRetriever.get, он последовательно решает массив из 27 элементов (как и ожидалось), но тест не подведет, независимо от значения expectedCount. Вот мой простой ручной тест:

tideRetriever.get(from, to).then(
    function(entries) { 
     console.log(entries, entries.length); 
    }, 
    function(err) { 
     console.log("Promise rejected", err); 
    } 
); 

Я также могу разместить источник для тестируемого модуля, если это необходимо.

Я что-то не понимаю о Mocha или should.js? Любая помощь будет принята с благодарностью.

ответ

7

UPDATE

В какой-то момент Мокко начал поддерживать возвращение Promise из теста вместо добавления done() обратных вызовов. Оригинальный ответ по-прежнему работает, но тест выглядит намного чище, с таким подходом:

it("should retrieve and parse tide CSV data", function() { 
    return tideRetriever.get(from, to).then(
     function(entries) { 
      entries.should.be.instanceof(Array).and.have.lengthOf(expectedCount); 
     } 
    ); 
}); 

Заканчивать this gist для полного примера.

ORIGINAL

ВНИМАНИЕ. Принятый ответ работает только с обычным асинхронным кодом, а не с Promises (какой автор использует).

Разница в том, что исключения, вызванные обратными вызовами Promise, не могут быть уловлены приложением (в нашем случае Mocha), и поэтому тест завершится неудачей по тайм-ауту, а не по фактическому утверждению. Утверждение может быть зарегистрировано или не зависит от реализации Promise. См. Дополнительную информацию об этом на when documentation.

Чтобы правильно обработать это с помощью обещаний, вы должны передать err объект вместо обратного вызова done() вместо его метания. Вы можете сделать это с помощью метода Promise.catch() (не в onRejection() обратном вызове Promise.then(), так как он не исключает исключения из onFulfilment() callback того же метода).Смотрите пример ниже:

describe("tide retriever", function() { 
    it("should retrieve and parse tide CSV data", function(done) { 
     tideRetriever.get(from, to).then(
      function(entries) { // resolve 
       entries.should.be.instanceof(Array).and.have.lengthOf(expectedCount); 
       done(); // test passes 
      }, 
      function(err) { // reject 
       done(err); // Promise rejected 
      } 
     ).catch(function (err) { 
      done(err); // should throwed assertion 
     }); 
    }); 
}); 

PSdone() обратного вызова используется в трех местах, чтобы охватить все возможные случаи. Однако обратный вызов onRejection() может быть полностью удален, если в нем нет никакой специальной логики. Promise.catch() будет обрабатывать отклонения и в этом случае.

+0

Вы забыли добавить «сделано» в качестве параметра функции – Chaoste

+0

@Chaoste спасибо, исправлено. –

4

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

describe("tide retriever", function() { 
    it("should retrieve and parse tide CSV data", function(done) { 
     tideRetriever.get(from, to).then(
      function(entries) { // resolve 
       entries.should.be.instanceof(Array).and.have.lengthOf(expectedCount); 
       done(); 
      }, 
      function(err) { // reject 
       should.fail("Promise rejected", err); 
       done(); 
      } 
     ); 
    }); 
}); 

Обратите внимание, что путь Мокко знает, что это испытание асинхронного и он должен ждать, пока done() не называются просто указав, что аргумент.

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

Больше информации на: http://mochajs.github.io/mocha/#asynchronous-code

+0

спасибо. Я думал, что функция 'done' была предназначена только для указания того, должен ли тест запускаться синхронно с другими тестами. – SimpleJ

+0

Я бы удвоил это, если мог. Важность передачи 'done' arg для теста (функция обратного вызова' it') легко пропустить, но источник большой путаницы! – Ben

Смежные вопросы