Как я могу проверить, что с помощью Sinon ожидалось (а не просто создано) обещание? - PullRequest
0 голосов
/ 03 октября 2019

Допустим, у меня есть функция:

const someAction = async(): Promise<string> => {
    /* do stuff */
};

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

someAction();

Который вместо этого должен был выглядеть так:

await someAction();

Теперь я могупроверьте, было ли выполнено это действие:

const actionStub = sinon.stub(someAction);
expect(actionStub).to.have.been.calledWith();

Но какой самый краткий способ проверить, что это обещание было получено?

Я понимаю, как реализовать это сам, но я подозреваю, что этодолжно быть, уже реализовано в sinon или sinon-chai, я просто не могу ничего найти.

1 Ответ

1 голос
/ 04 октября 2019

Я, конечно, могу сказать, что ничего подобного не существует в sinon или sinon-chai.

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

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

let actionComplete = false;
const actionStub = sinon.stub(someAction).callsFake(() => {
    return new Promise((resolve) => {
        setImmediate(() => {
            actionComplete = true;
            resolve();
        });
    });
});

expect(actionStub).to.have.been.calledWith();
expect(actionComplete).to.be.true;

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

Например, вы можете выполнить этот проход с помощью чего-то подобного в тестируемом коде:

someAction();
await new Promise((resolve) => {
    setImmediate(() => resolve());
});

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

const actionStub = sinon.stub(someAction).resolves();

// In one test
expect(actionStub).to.have.been.calledWith();

// In another test
const actionError = new Error('omg bad error');
actionStub.rejects(actionError);

// Assuming your test framework supports returning promises from tests.
return functionUnderTest()
    .then(() => {
        throw new Error('Promise should have rejected');
    }, (err) => {
        expect(err).to.equal(actionError);
    });

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

...