#javascript #node.js #asynchronous #mocha.js
#javascript #node.js #асинхронный #mocha.js
Вопрос:
Я тестирую асинхронный метод, который возвращает некоторые данные из веб-запроса, используя собственный метод https.request() в NodeJS. Я использую mocha, chai и sinon с соответствующими расширениями для каждого.
Метод, который я тестирую, по сути, оборачивает шаблонный код https.request(), предоставленный в документах NodeJS, в обещание и разрешает при получении события ответа ‘end’ или отклоняет, если получено событие запроса ‘error’. Биты, относящиеся к обсуждению, выглядят следующим образом:
async fetch(...) {
// setup
return new Promise((resolve, reject) => {
const req = https.request(url, opts, (res) => {
// handle response events
});
req.on('error', (e) => {
logger.error(e); // <-- this is what i want to verify
reject(e);
});
req.end();
});
}
Как указано в комментарии, я хочу проверить, что если выдается событие ошибки запроса, ошибка регистрируется правильно. Это то, что я сейчас делаю для достижения этой цели:
it('should log request error events', async () => {
const sut = new MyService();
const err = new Error('boom');
const req = new EventEmitter();
req.end = sinon.fake();
const res = new EventEmitter();
sinon.stub(logger, 'error');
sinon.stub(https, 'request').callsFake((url, opt, cb) => {
cb(res);
return req;
});
try {
const response = sut.fetch(...);
req.emit('error', err);
await response;
} catch() {}
logger.error.should.have.been.calledOnceWith(err);
});
Это похоже на взлом, но я не могу понять, как это сделать правильно, используя обычные шаблоны. Основная проблема в том, что мне нужно выдать событие ошибки после вызова метода, но до того, как обещание будет выполнено, и я не вижу, как это сделать, если я возвращаю обещание, как вы обычно делаете с mocha.
Комментарии:
1. Я не вижу в этом ничего плохого. В качестве альтернативы вы можете поместить a
setTimeout(() => req.emit('error', err), demoDelay);
внутриrequest
подделки, а затем записатьawait sut.fetch(…);
, но в любом случае все в порядке.2. Что вы имеете в виду, когда говорите: » Я не вижу, как это сделать, если я возвращаю обещание, как вы обычно делаете с mocha». ? Ваша
async
функция возвращает обещание mocha.3. @Bergi Ваша идея setTimeout дала мне ответ, который я искал, спасибо!
Ответ №1:
Я должен был подумать об этом, но комментарий @Bergi об использовании setTimeout() в подделке дал мне идею, и теперь я работаю с предпочтительным синтаксисом:
it('should log request error events', () => {
const sut = new MyService();
const err = new Error('boom');
const req = new EventEmitter();
req.end = sinon.fake();
const res = new EventEmitter();
sinon.stub(logger, 'error');
sinon.stub(https, 'request').callsFake((url, opt, cb) => {
cb(res);
setTimeout(() => { req.emit('error', err); });
return req;
});
return sut.fetch(...).should.eventually.be.rejectedWith(err)
.then(() => {
logger.error.should.have.been.calledOnceWith(err);
});
});
Мне не нравится добавлять какие-либо задержки в модульные тесты, если я специально не тестирую отложенную функциональность, поэтому я использовал setTimeout() с задержкой 0, чтобы просто отправить вызов emit в конец очереди сообщений. Переместив его в поддельный, я смог просто использовать цепочку обещаний для проверки вызова метода logger.
Комментарии:
1. Ваш исходный код также использует цепочку обещаний, единственное отличие состоит в том, что он сохраняет обещание во временной переменной
response
. Я бы подумал, чтоasync
await
было бы предпочтительнее использовать синтаксис / для цепочки вместо.then()
вызовов?2. @Bergi Я все еще учусь, но, думаю, я понимаю вашу точку зрения в том, что на самом деле происходит за кулисами. В исходном коде, несмотря на то, что проверка регистратора является отдельным оператором, поскольку это асинхронная функция, операторы после await объединяются в цепочку так же, как если бы вы вызывали then() . Это довольно проницательно, спасибо! И да, в обычном коде я предпочитаю async / await, но в случае модульных тестов я пытаюсь поддерживать согласованный стиль BDD, поэтому эта версия больше похожа на другие тесты, даже если есть небольшая разница.