Тестовый обратный вызов в конце цепочки обещаний

Я имею дело с обратными вызовами в стиле смешивания кода и обещаниями Bluebird, и мне нужно написать несколько тестов для этого.

Особенно, cache.js подвергает init() функция, которая работает с обещаниями. Затем он вызывается doSomething() функция в другом файле (например, index.js) который в свою очередь принимает обратный вызов, который должен быть вызван в конце init(),

Псевдокод выглядит следующим образом:

// [ cache.js ]
function init() {
  return performInitialisation()
    .then((result) => return result);
}


// [ index.js ]
var cache = require('./cache');

function doSomething(callback) {
  console.log('Enter');

  cache.init()
    .then(() => {
      console.log('Invoking callback');
      callback(null);
    })
    .catch((err) => {
      console.log('Invoking callback with error');
      callback(err);
    });

  console.log('Exit');
}

Возможный модульный тест может быть (показывая только соответствующий код):

// [ index.test.js ]
...
var mockCache = sinon.mock(cache);
...
it('calls the callback on success', function(done) {
  mockCache.expects('init')
    .resolves({});

  var callback = sinon.spy();

  doSomething(callback);
  expect(callback).to.have.been.calledOnce;
  done();
});

Этот тест проходит, однако изменяет ожидание на not.have.been.calledOnce также проходит, что неправильно.

Кроме того, консольные журналы не в порядке:

Enter
Exit
Invoking callback

Я рассмотрел несколько возможностей, ни одна из которых не сработала:

  • Использование chai-as-обещано, например expect(callback).to.eventually.have.been.calledOnce;

  • Рефакторинг doSomething() быть просто:

    function doSomething (callback) {cache.init ().asCallback (callback); }

Может кто-нибудь помочь мне понять, что я делаю неправильно, и как я могу это исправить, пожалуйста?

2 ответа

Решение

журналы консоли не в порядке

Журналы в правильном порядке, потому что ваш Promise будет асинхронным, то есть внутренняя консоль будет регистрировать вызовы then & catch будет работать на следующем тике.

Относительно того, почему тест не пройден, является результатом нескольких проблем, во-первых, у вас, похоже, нет sinon-chai настроен правильно, или в лучшем случае ваш calledOnce утверждение не включается. Просто для подтверждения, верхняя часть вашего тестового файла должна выглядеть примерно так:

const chai = require("chai");
const sinonChai = require("sinon-chai");

chai.use(sinonChai);

Если у вас это есть, но оно все еще не работает должным образом, возможно, стоит открыть sinon-chai lib, однако, простой обходной путь состоит в том, чтобы перейти к утверждениям sinon, например:

sinon.assert.calledOnce(callback)

Во-вторых, когда вы в конце концов исправите это, вы, вероятно, обнаружите, что тест теперь не будет выполнен... каждый раз. Причина в том, что в вашем тесте возникла та же проблема, что и при ведении журнала - ваше утверждение до того, как внутреннее обещание успело решить. Самый простой способ исправить это на самом деле с помощью вашего done обработчик из мокко, как ваше утверждение

mockCache.expects('init').resolves({});
doSomething(() => done());

Другими словами, если done получить вызов, то вы знаете, что обратный вызов был вызван:)

После комментария James я пересмотрел свои тесты следующим образом:

it('calls the callback on success', function(done) {
  mockCache.expects('init')
    .resolves({});

  doSomething(done);
});

it('calls the callback on error', function(done) {
  mockCache.expects('init')
    .rejects('Error');

  doSomething((err) => {
    if (err === 'Error') {
      done();
    } else {
      done(err);
    }
  });
});
Другие вопросы по тегам