Убедитесь, что исключение выбрано с использованием Mocha/Chai и async/wait
Я изо всех сил пытаюсь разработать лучший способ проверить, что обещание отклонено в тесте Mocha при использовании async/wait.
Вот пример, который работает, но мне не нравится, что should.be.rejectedWith
возвращает обещание, которое должно быть возвращено из тестовой функции для правильной оценки. Использование async/await устраняет это требование для тестирования значений (как я делаю для результата wins()
ниже), и я чувствую, что, вероятно, я забуду оператор возврата в какой-то момент, и в этом случае тест всегда будет проходить,
// Always succeeds
function wins() {
return new Promise(function(resolve, reject) {
resolve('Winner');
});
}
// Always fails with an error
function fails() {
return new Promise(function(resolve, reject) {
reject('Contrived Error');
});
}
it('throws an error', async () => {
let r = await wins();
r.should.equal('Winner');
return fails().should.be.rejectedWith('Contrived Error');
});
Похоже, должно быть возможно использовать тот факт, что async/await переводит отказ на исключения и объединяет это с Chai should.throw, но я не смог определить правильный синтаксис.
В идеале это сработает, но не похоже:
it('throws an error', async () => {
let r = await wins();
r.should.equal('Winner');
(await fails()).should.throw(Error);
});
Ответы
Ответ 1
Проблема с этим подходом заключается в том, что (await fails()).should.throw(Error)
не имеет смысла.
await
разрешает Promise
. Если Promise
отвергает, он выбрасывает отклоненное значение.
Итак, (await fails()).should.throw(Error)
никогда не может работать: если fails()
отклоняется, возникает ошибка, и .should.throw(Error)
никогда не выполняется.
Самый идиоматический вариант, который у вас есть, - использовать свойство Chai rejectedWith
, как вы показали в своем вопросе.
Вот краткий пример. Не так много отличается от того, что вы продемонстрировали в своем вопросе; Я просто использую async
функции для wins()
и fails()
и expect
а не should
. Конечно, вы можете использовать функции, которые возвращают Promise
и chai.should
просто отлично.
const chai = require('chai')
const expect = chai.expect
chai.use(require('chai-as-promised'))
// Always succeeds
async function wins() {
return 'Winner'
}
// Always fails with an error
async function fails() {
throw new Error('Contrived Error')
}
it('wins() returns Winner', async () => {
expect(await wins()).to.equal('Winner')
})
it('fails() throws Error', async () => {
await expect(fails()).to.be.rejectedWith(Error)
})
Если вам нравится, чтобы ваш тест wins()
больше напоминал тест fails()
, вы можете написать свой тест wins()
следующим образом:
it('wins() returns Winner', async () => {
await expect(wins()).to.eventually.equal('Winner')
})
Ключевым моментом, который следует помнить в любом из этих примеров, является то, что chai-as-promised
возвращения обещают его функции, такие как rejectedWith
и в eventually.something
. Поэтому вы должны await
их в контексте async
тестовой функции, иначе проваливаются условия:
async function wins() {
return 'Loser'
}
async function fails() {
return 'Winner'
}
it('wins() returns Winner', async () => {
expect(wins()).to.eventually.equal('Winner')
})
it('fails() throws Error', async () => {
expect(fails()).to.be.rejectedWith(Error)
})
Если вы проверили тесты с приведенным выше кодом, вы получите следующее:
$ npm test
> [email protected] test /home/vsimonian/code/mocha-chai-async
> mocha .
√ wins() returns Winner
(node:13836) UnhandledPromiseRejectionWarning: Unhandled promise rejection (rej
ection id: 1): AssertionError: expected 'Loser' to equal 'Winner'
(node:13836) [DEP0018] DeprecationWarning: Unhandled promise rejections are dep
recated. In the future, promise rejections that are not handled will terminate
the Node.js process with a non-zero exit code.
√ fails() throws Error
(node:13836) UnhandledPromiseRejectionWarning: Unhandled promise rejection (rej
ection id: 2): AssertionError: expected promise to be rejected with 'Error' but
it was fulfilled with 'Winner'
2 passing (11ms)
Как вы можете видеть, утверждения хаи на самом деле потерпели неудачу, но им не удалось в контексте обещания, что никто никогда не await
или не catch
. Таким образом, Mocha не видит сбоя и отмечает тесты, как если бы они проходили, но Node.js (в поведении, которое изменится в будущем, как указано выше) печатает необработанные отклонения к терминалу.
Ответ 2
Это мое решение проблемы.
try {
// here the function that i expect to will return an errror
let walletid = await Network.submitTransaction(transaction)
} catch (error) {
// assign error.message to ErrorMessage
var ErrorMessage = error.message;
// catch it and re throw it in assret.throws fn and pass the error.message as argument and assert it is the same message expected
assert.throws(() => { throw new Error(ErrorMessage) },'This user already exists');
}
// here assert that ErrorMessage is Defined ; if it is not defined it means that no error occurs
assert.isDefined(ErrorMessage);
Ответ 3
Я использую пользовательскую функцию, как это:
const expectThrowsAsync = async (method, errorMessage) => {
let error = null
try {
await method()
}
catch (err) {
error = err
}
expect(error).to.be.an('Error')
if (errorMessage) {
expect(error.message).to.equal(errorMessage)
}
}
а затем для обычной асинхронной функции, например:
const login = async (username, password) => {
if (!username || !password) {
throw new Error("Invalid username or password")
}
//await service.login(username, password)
}
Я пишу тесты так:
describe('login tests', () => {
it('should throw validation error when not providing username or passsword', async () => {
await expectThrowsAsync(() => login())
await expectThrowsAsync(() => login(), "Invalid username or password")
await expectThrowsAsync(() => login("username"))
await expectThrowsAsync(() => login("username"), "Invalid username or password")
await expectThrowsAsync(() => login(null, "password"))
await expectThrowsAsync(() => login(null, "password"), "Invalid username or password")
//login("username","password") will not throw an exception, so expectation will fail
//await expectThrowsAsync(() => login("username", "password"))
})
})
Ответ 4
Этот пример работает только с Node!
Когда вы используете Mocha в Node.js, вы можете использовать doesNotReject()
или rejects()
, для обоих требуется функция, которая возвращает обещание.
Пример того, когда он должен отклонить:
await rejects(testFunction());
see: https://nodejs.org/api/assert.html#assert_assert_rejects_asyncfn_error_message
Пример того, когда он не должен отклонять:
await doesNotReject(testFunction());
see: https://nodejs.org/api/assert.html#assert_assert_doesnotreject_asyncfn_error_message
Ответ 5
Если вы тестируете свою функцию Promised, в тесте необходимо обернуть код внутри try/catch, а ожидаемый() должен быть внутри блока ошибки catch
const loserFunc = function(...args) {
return new Promise((resolve, rejected) => {
// some code
return rejected('fail because...');
});
};
Итак, тогда в вашем тесте
it('it should failt to loserFunc', async function() {
try {
await loserFunc(param1, param2, ...);
} catch(e) {
expect(e).to.be.a('string');
expect(e).to.be.equals('fail because...');
}
});
Это мой подход, не знаю лучшего пути.
Ответ 6
Вы можете использовать async/await
и should
для простой проверки
it('throws an error', async () => {
try {
let r = await wins();
r.should.equal('Winner');
await fails();
} catch (error) {
error.should.be.Error();
error.should.have.value("message", "Contrived Error");
}
});