Testando lançamento de exceções com Jest

dotmendes

Júnior Mendes

Posted on March 19, 2020

Testando lançamento de exceções com Jest

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 e it;
  • 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 };
Enter fullscreen mode Exit fullscreen mode

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');
  }
});

Enter fullscreen mode Exit fullscreen mode

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();
});
Enter fullscreen mode Exit fullscreen mode

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();
});
Enter fullscreen mode Exit fullscreen mode

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();
});
Enter fullscreen mode Exit fullscreen mode

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.

💖 💪 🙅 🚩
dotmendes
Júnior Mendes

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