Testando lançamento de exceções com Jest
Júnior Mendes
Posted on March 19, 2020
Testar se uma função trata corretamente erros é algo comum em testes unitários. Quando esse tratamento ocorre por meio de exceções, é fácil se perder frente à quantidade de possibilidades - além do fato de não ser tão trivial quanto parece.
Antes de mais nada, neste tutorial eu assumo que:
- Você está familiarizado com
async/await
; - Você já utilizou o jest e sabe o contexto de termos como
describe
eit
; - Você sabe lidar com exceções.
O problema
Imagine as seguintes funções:
// funcs.js
const foo = () => {
throw new Error('Something wrong');
}
const goo = async () => {
throw new Error('Something wrong - async');
}
const boo = (n) => {
if (n < 0) {
throw new Error('Something wrong - params');
}
}
const doo = async (n) => {
if (n < 0) {
throw new Error('Something wrong - async + params');
}
}
export default { foo, goo, boo, doo };
Como seria possível testar se a exceção é lançada corretamente? Você pode pensar em algo assim para a função foo
, por exemplo:
// funcs.test.js
import { foo } from './funcs.js'
test('Should throw exception', () => {
try {
foo();
} catch (e) {
expect(e.message).toBe('Something wrong');
}
});
Contudo esse teste não seria muito eficiente, uma vez que ele poderia passar quando nenhuma exceção está sendo lançada. Além disso, o Jest nos possibilita fazer algo muito mais simples, sem a necessidade de escrever uma estrutura tão grande.
Funções Síncronas sem parâmetros (foo)
Esse é o caso mais simples. Basta passar a função como parâmetro para o expect
e utilizar o método toThrow
(ou similares). Nesse caso, teríamos algo assim:
import { foo } from './funcs.js'
test('Should throw exception', () => {
expect(foo).toThrow();
});
Caso queira verificar o tipo de erro, você pode utilizar o
toThrowError
:expect(foo).toThrowError(new Error('Something wrong'));
Funções Síncronas com parâmetros (boo)
Aqui temos uma pequena diferença. Vamos chamar a função com um dado que deve gerar exceções dentro de uma função anônima e passar esta para o expect
:
import { boo } from './funcs.js'
test('When n < 0, expect to throw Error ', () => {
expect(() => boo(-1)).toThrow();
});
Funções assíncronas (goo, doo)
Aqui teremos duas mudanças. A primeira é que a função passada para o test
/it
deve ser assíncrona. A outra é que vamos chamar a função diretamente dentro do expect
e testar se a Promise será rejeitada e retornará um erro:
import { goo, doo } from './funcs.js'
test('Expect to throw Error ', async () => {
await expect(goo()).rejects.toThrow();
});
test('When n < 0, expect to throw Error ', async () => {
await expect(doo(-1)).rejects.toThrow();
});
Nas funções assíncronas podemos realizar chamadas diretamente pelo fato delas não lançarem a exceção diretamente, mas retornarem Promises rejeitadas. Caso o mesmo seja feito para funções síncronas, o teste será interrompido e não funcionará corretamente.
Posted on March 19, 2020
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.
Related
March 19, 2024