Movatterモバイル変換


[0]ホーム

URL:


Skip to content
DEV Community
Log in Create account

DEV Community

Romildo Junior
Romildo Junior

Posted on

     

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 comasync/await;
  • Você já utilizou o jest e sabe o contexto de termos comodescribe eit;
  • Você sabe lidar com exceções.

O problema

Imagine as seguintes funções:

// funcs.jsconstfoo=()=>{thrownewError('Something wrong');}constgoo=async()=>{thrownewError('Something wrong - async');}constboo=(n)=>{if(n<0){thrownewError('Something wrong - params');}}constdoo=async(n)=>{if(n<0){thrownewError('Something wrong - async + params');}}exportdefault{foo,goo,boo,doo};
Enter fullscreen modeExit fullscreen mode

Como seria possível testar se a exceção é lançada corretamente? Você pode pensar em algo assim para a funçãofoo, por exemplo:

// funcs.test.jsimport{foo}from'./funcs.js'test('Should throw exception',()=>{try{foo();}catch(e){expect(e.message).toBe('Something wrong');}});
Enter fullscreen modeExit 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 oexpect e utilizar o métodotoThrow (ou similares). Nesse caso, teríamos algo assim:

import{foo}from'./funcs.js'test('Should throw exception',()=>{expect(foo).toThrow();});
Enter fullscreen modeExit fullscreen mode

Caso queira verificar o tipo de erro, você pode utilizar otoThrowError:

expect(foo).toThrowError(newError('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 oexpect:

import{boo}from'./funcs.js'test('When n < 0, expect to throw Error',()=>{expect(()=>boo(-1)).toThrow();});
Enter fullscreen modeExit fullscreen mode

Funções assíncronas (goo, doo)

Aqui teremos duas mudanças. A primeira é que a função passada para otest/it deve ser assíncrona. A outra é que vamos chamar a função diretamente dentro doexpect e testar se a Promise será rejeitada e retornará um erro:

import{goo,doo}from'./funcs.js'test('Expect to throw Error',async()=>{awaitexpect(goo()).rejects.toThrow();});test('When n < 0, expect to throw Error',async()=>{awaitexpect(doo(-1)).rejects.toThrow();});
Enter fullscreen modeExit 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.

Top comments(4)

Subscribe
pic
Create template

Templates let you quickly answer FAQs or store snippets for re-use.

Dismiss
CollapseExpand
 
fabimendes profile image
Fabi Mendes
  • Work
    Front-end Developer
  • Joined
• Edited on• Edited

Júnior, estou iniciando nos testes e talvez você possa me ajudar... Tenho uma função de login com try/catch que recebe um email e um password, se o e-mail e senha não batem ela exibe um alert na tela. Montei o teste para essa função, passando os parâmetros que o backend aceita, mas o teste quebra no catch. Vou colá-los aqui:

Função login:

"async function Login(loginData) {
try {
const response = await api.post('/user/login', loginData);
setUser(response.data);
localStorage.setItem('@App:user', JSON.stringify(response.data));
localStorage.setItem('@App:token', response.data.id);
api.defaults.headers.Authorization =Bearer ${response.data.id};
} catch(error) {
alert(Usuário ou senha inválidos!);
}
}"

Teste:

"describe('Login function', () => {
it('Set the user to logged', () => {
const TestComponent = () => {
const { Login, logged } = useAuth();
const loginData = {email:'teste@front.com', password:'teste123'};
return (
<>

{logged.toString()}

</>
);
}
render();
expect(screen.getByTestId('status')).toHaveTextContent('false')
fireEvent.click(screen.getByTestId('button'))
expect(screen.getByTestId('status')).toHaveTextContent('true')
})
});"

Sabe me dizer o que está errado? Agradeço demais o help, é muito difícil achar conteúdo sobre testes, principalmente para funções com providers..rsrs

CollapseExpand
 
dotmendes profile image
Romildo Junior
I'm a Brazilian back-end developer, with some front-end and devops powers. I do not play soccer well :')
  • Location
    Recife, Brazil
  • Education
    Electronic Engineering (incomplete) @ UFPE
  • Work
    Javascript / Typescript Developer
  • Joined

Oi Fabi, tudo bem? Percebi que nesse trecho que tu me mandou, não tem nenhum mock pra API do Axios. Isso foi apenas por simplicidade ou de fato está batendo no backend durante o teste? Talvez sso poderia fazer com que a chamada pra API sempre retorne um erro.

De toda forma, o intuito seria testar apenas a lógica da função Login? Penso que poderia ser mais simples, se for o caso, testar ela diretamente, sem usar esse TestComponent.

CollapseExpand
 
fabimendes profile image
Fabi Mendes
  • Work
    Front-end Developer
  • Joined

Então, fiz um teste com mock pra testar se a função Login está sendo chamada ao clicar no botão, esta parte está ok.
Mas eu queria testar neste caso o estado do usuário, se após os dados serem validados o status dele passa para logged=true. Fiz a função enviado os dados para bater no backend(api) para testar essa validação... Tenho pouca experiência com testes, talvez eu esteja testando algo indevido também, rsrsrs
Este era um passo de um teste que me enviaram onde pediam testes de snapshot com jest...não consegui visualizar como o snapshot poderia se encaixar neste contexto, então tentei fazer assim...rs

CollapseExpand
 
ricardomorato profile image
Ricardo Morato Rocha
I'm a software engineer who loves learning and testing new things. Currently focusing on Typescript, Python, and DSA.
  • Email
  • Location
    Recife/Brazil
  • Education
    Computer engineering undergraduate at the Federal University of Pernambuco | Brazil
  • Pronouns
    he/him
  • Work
    Software Engineer
  • Joined

Ótimo conteúdo Júnior! Ansioso para mais!

Are you sure you want to hide this comment? It will become hidden in your post, but will still be visible via the comment'spermalink.

For further actions, you may consider blocking this person and/orreporting abuse

I'm a Brazilian back-end developer, with some front-end and devops powers. I do not play soccer well :')
  • Location
    Recife, Brazil
  • Education
    Electronic Engineering (incomplete) @ UFPE
  • Work
    Javascript / Typescript Developer
  • Joined

More fromRomildo Junior

DEV Community

We're a place where coders share, stay up-to-date and grow their careers.

Log in Create account

[8]ページ先頭

©2009-2025 Movatter.jp