O React Native está entre as bibliotecas mais comumente usadas para a construção de aplicativos móveis atualmente. Neste guia, exploraremos o teste de unidade em aplicativos React Native, abrangendo benefícios, práticas recomendadas, estruturas de teste e muito mais.
O que é teste de unidade?
O teste de unidade é a prática de testar pedaços pequenos e isolados de código. React Native coloca assim:
Os testes de unidade cobrem as menores partes do código, como funções ou classes individuais.
Portanto, o teste de unidade envolve o teste de funções, classes, componentes-todos os pequenos pedaços em nosso projeto. Podemos testar cada um deles individualmente para garantir que funcionam.
Considere o exemplo abaixo, um snippet de um arquivo utils.js
em um projeto JavaScript:
//utils.js função toJSON () {...} função convertToSLAs (args) {...} função hourToMins (hora) {...} exportar {toJSON, convertToSLAs, hourToMins}
O arquivo contém funções que realizam diferentes ações. Podemos testar a unidade de cada função neste arquivo, o que significa que podemos testar cada uma das funções independentemente em diferentes condições para garantir que cada uma funcione conforme o esperado.
//test/_tests_.js descrever ("testes toJSON", ()=> { it ("deve retornar o objeto", ()=> { esperar (toJSON (..)). toBe (...) ... }); ... }); describe ("testes convertToSLAs", ()=> { it ("deve retornar verdadeiro", ()=> { esperar (convertToSLAs (...)). toBe (true) ... }); ... }); descrever ("hourtoMins", ()=> { it ("deve ser verdadeiro", ()=> { esperar (hourToMins (...)). toBe (true) ... }); ... });
Como você pode ver, escrevemos testes para cada função. Cada suíte de teste contém uma série de testes que cobrem totalmente o trabalho da função.
Frameworks de teste como Jest, Mocha, Jasmine e outros fornecem resultados detalhados dos testes. Quaisquer testes que falharem nas condições são marcados como reprovados, indicando que precisam de um exame mais aprofundado; é claro, os testes aprovados são marcados como aprovados.
Pense em uma falha no teste como uma coisa boa. Quando um teste falha, geralmente significa que algo não está certo; isso nos dá a oportunidade de corrigir o problema antes que ele afete nossos usuários. Os testes de unidade são ótimos para fornecer feedback rápido e fornecer confiança de que nossas funções funcionarão conforme o esperado na produção.
Práticas recomendadas para testes de estruturação
Os testes devem ser legíveis e sustentáveis. O teste deve ser curto e testar uma condição de cada vez. Considere o teste abaixo, baseado em uma função it
:
it ("deve ser verdadeiro", ()=> { expect (hourToMins (3)). toBe (180); expect (hourToMins (5)). toBe (300); expect (hourToMins (null)). toBe (null); });
O teste acima possui várias condições em apenas um único teste, o que o torna ambíguo. As três condições são:
- Após 3 horas,
ele
retorna 180 minutos - Após 5 horas,
ele
retorna 300 minutos - Quando
null
é passado,ele
retornanull
Em vez disso, cada condição acima deve ser um teste separado:
it ("deve retornar 180", ()=> { expect (hourToMins (3)). toBe (180); }); it ("deve retornar 300", ()=> { expect (hourToMins (5)). toBe (300); }); it ("deve retornar nulo", ()=> { expect (hourToMins (null)). toBe (null); });
Isso torna tudo muito mais claro.
Os testes também devem ser tão descritivos quanto possível. Nos testes acima, as descrições não são claras; a descrição deve ser clara o suficiente para transmitir o que está sendo testado em relação a uma condição.
Os documentos do React Native fornecem algumas práticas recomendadas :
Faça o seu melhor para cobrir o seguinte:
- Dado-alguma pré-condição.
- Quando-alguma ação executada pela função que você está testando.
- Então-o resultado esperado.
Isso também é conhecido como AAA (Arrange, Act, Assert).
Então, vamos tornar nossos testes mais descritivos:
it ("dadas 3 horas, hourToMins deve retornar 180", ()=> { expect (hourToMins (3)). toBe (180); }); it ("dado nulo, hourToMins deve retornar nulo", ()=> { expect (hourToMins (null)). toBe (null); });
Lá vamos nós-muito mais claro.
Teste de unidade usando Jest e Enzyme
Existem muitas estruturas de teste que podemos usar para testar aplicativos React Native, incluindo, mas não se limitando a:
- Mocha
- Brincadeira
- Jasmim
- Pesadelo
- WebDriver
Todas essas são boas opções para testar aplicativos baseados em JS. Jest e Enzyme são particularmente bons e ambos vêm muito recomendado para testar aplicativos baseados em React. Mas, como o React Native não é para aplicativos da web, nem o Jest nem o Enzyme têm um adaptador React Native.
Felizmente, existem algumas bibliotecas que podem nos ajudar com testes de unidade para aplicativos React Native:
Jest fornece o ambiente de teste, e React Native Testing Library oferece uma solução leve para testar componentes React Native. O React Test Renderer fornece um renderizador React que podemos usar para renderizar componentes React em objetos JavaScript puros, sem depender do DOM ou de um ambiente móvel nativo.
O teste de unidade no React Native também cobre os testes de componentes. Os componentes são unidades fundamentais de qualquer aplicativo React Native; cada componente renderiza sua própria seção do aplicativo, e os usuários interagem diretamente com sua saída.
Existem duas coisas que testamos nos componentes:
- Interação , o que significa que o componente responde corretamente à interação do usuário
- Saída , o que significa que o componente renderiza a saída correta
Configurando nosso ambiente de teste
A partir daqui, exploraremos como adicionar funcionalidade de teste ao nosso aplicativo React Native. Primeiro, vamos criar um novo projeto React Native instalando a ferramenta expo-cli globalmente:
yarn global add expo-cli
A seguir, criaremos um novo projeto React Native chamado react-native-test:
expo init react-native-test cd react-nativo-test yarn start # você também pode usar: expo start
Isso iniciará um servidor de desenvolvimento. Usar expo-cli para dar suporte ao nosso projeto React Native configurará o ambiente de teste para nós automaticamente:
//package.json ... "scripts": { ... "test":"jest--watchAll" }, "jest": { "preset":"jest-expo" } ...
Tudo está pronto para nós. Tudo o que precisamos fazer é executar yarn test
em nosso terminal para executar os arquivos de teste.
Agora, vamos abrir o projeto no VS Code, abrir o terminal integrado e executar o yarn test
. Veremos Jest executar os arquivos de teste e ficar no modo de observação, observando os arquivos para executá-los novamente se a entrada for feita.
PASSAR componentes/__ testes __/StyledText-test.js (5.018s) ✓ renderiza corretamente (3108ms) ›1 instantâneo gravado. Resumo instantâneo ›1 instantâneo escrito a partir de 1 suíte de teste. Suítes de teste: 1 aprovado, 1 total Testes: 1 aprovado, 1 total Instantâneos: 1 escrito, 1 total Tempo: 5.1s Executei todas as suítes de teste. Assistir ao uso ›Pressione f para executar apenas os testes que falharam. ›Pressione o para apenas executar testes relacionados a arquivos alterados. ›Pressione p para filtrar por um padrão de regex de nome de arquivo. ›Pressione t para filtrar por um padrão de regex de nome de teste. ›Pressione q para sair do modo de relógio. ›Pressione Enter para iniciar uma execução de teste.
Agora podemos instalar a Biblioteca de testes nativos do React:
yarn add--dev @ testing-library/react-native
E é isso-estamos prontos para começar a escrever nossos testes de unidade.
Componentes de teste
Digamos que temos um componente Button.tsx
na pasta components
:
import React from"react"; import {Text, TouchableOpacity} de"react-native"; botão de função ({estilos, filhos}) { Retorna (); } botão padrão de exportação; {crianças}
Podemos escrever um teste para determinar se o componente Botão
é renderizado corretamente:
//__testes__ import * as React from"react"; botão de importação de"../Button"; importar renderizador de"react-test-renderer"; ele (`renderiza corretamente`, ()=> { const tree=renderer.create (); esperar (árvore).toMatchSnapshot (); });
Agora vamos escrever um teste para o componente App
:
import * as React from"react"; importar renderizador de"react-test-renderer"; importar App de"../App"; ele (`renderiza corretamente`, ()=> { const tree=renderer.create (). toJSON (); expect (tree.children.length).toBe (1); });
O App
renderiza um DOM com um único filho, então este teste passa.
Zombaria
Podemos simular a implementação real com uma versão fictícia que imita a real. Zombar torna os testes muito mais rápidos, especialmente aqueles que envolvem atividade na Internet. Jest nos permite adicionar nossas implementações simuladas-vamos ver como isso é feito.
Vamos testar um componente de apresentação:
function TodoItem ({todo, editTodoItem, deleteTodoItem}: TodoProps) { Retorna ( <>{todo.todoText} editTodoItem (todo)} > Editar deleteTodoItem (todo)} > > ); }Del
O componente TodoItem
renderiza um todo
. Observe que o componente TodoItem
espera um objeto todo
e as funções chamadas quando os botões Del
e Editar
são clicados.
Para testar isso, teremos que simular os adereços de função.
it ("excluir e editar um todo", ()=> { const mockEditTodoItemFn=jest.fn (); const mockDeleteTodoItemFn=jest.fn (); const {getByText}=render (); fireEvent.press (getByText ("Editar")); fireEvent.press (getByText ("Del")); esperar (mockEditTodoItemFn).toBeCalledWith ({ 1: {todoText:"ir à igreja"}, }); expect (mockDeleteTodoItemFn).toBeCalledWith ({ 1: {todoText:"ir à igreja"}, }); });
Usamos o fn ()
de Jest para criar funções fictícias mockDeleteTodoItemFn
e mockEditTodoItemFn
, então os atribuímos ao editTodoItem
e deleteTodoItem
props. As funções simuladas são chamadas quando um usuário pressiona os botões Del
ou Editar
. Isso garante que os botões funcionarão em produção quando as funções reais forem passadas.
Também podemos simular valores de retorno:
it ("excluir e editar um todo", ()=> { const mockEditTodoItemFn=jest.fn (); mockEditTodoItemFn.mockReturnValue ({editado: verdadeiro}); const mockDeleteTodoItemFn=jest.fn (); mockDeleteTodoItemFn.mockReturnValue ({excluído: true}); const {getByText}=render (); fireEvent.press (getByText ("Editar")); fireEvent.press (getByText ("Del")); esperar (mockEditTodoItemFn.mock.results [0].value).toBe ({ editado: verdadeiro, }); expect (mockDeleteTodoItemFn.mock.results [0].value).toBe ({ excluído: verdadeiro, }); });
Chamamos o método .mockReturnValue (...)
nas funções fictícias com os valores que queremos retornados quando as funções são chamadas. Isso nos ajuda a testar nossas funções sobre o tipo de valor que ele retorna.
A propriedade .mock.results
contém a matriz de resultados das funções simuladas que chamamos. A partir disso, pudemos recuperar os valores retornados e testá-los em relação aos valores esperados.
Também podemos simular chamadas de API. Usaremos Axios para realizar chamadas HTTP para nossas APIs. Veja como simulamos métodos Axios como get
, post
, delete
e put
:
... importar axios de"axios"; exportar função padrão Home () { const [todos, setTodos]=useState ([]); useEffect (async ()=> { const result=await axios.get ("http://localhost: 1337/todos"); setTodos (resultado?.data); }, []); const addTodo=async (todoText)=> { if (todoText && todoText.length> 0) { const result=await axios.post ("http://localhost: 1337/todos", { todoText: todoText, }); setTodos ([... todos, resultado?.data]); } }; Retorna ({todos.map ((todo, i)=> { {todo} })} ); }
Temos um componente que carrega e envia as tarefas a um servidor. Para testar este componente, precisaremos simular a chamada HTTP no Axios:
jest.mock ("axios"); it ("o componente pode carregar todos, quando montado.", ()=> { const resp={ dados: [{todoText:"ir para a igreja"}, {todoText:"ir para o mercado"}], }; axios.get.mockResolvedValue (resp); const {getByText}=render (); const todos=[getByText ("ir à igreja"), getByText ("ir ao mercado")]; expect (todos.length).toBe (2); });
Aqui, nós simulamos o método Axios get
. Quando o componente Home
carrega os itens por-fazer via axios.get
, nosso mock é chamado e responde com uma resposta mock. Mais sobre mocking pode ser encontrado aqui .
Teste de interações do usuário
Também devemos testar as interações do usuário em nossos componentes React Native-interações como pressionar um botão, inserir texto, rolar uma lista e assim por diante.
A biblioteca de testes do React Native é um ótimo recurso para testar as interações do usuário nos componentes do React Native. Ele fornece métodos como getByPlaceholder
, getByText
e getAllByText
que podemos usar para obter os elementos ou texto da saída renderizada como nós. Podemos então interagir com os nós renderizados como se estivéssemos realmente fazendo isso em um navegador.
Vejamos nosso exemplo anterior:
it ("excluir e editar um todo", ()=> { const mockEditTodoItemFn=jest.fn (); mockEditTodoItemFn.mockReturnValue ({editado: verdadeiro}); const mockDeleteTodoItemFn=jest.fn (); mockDeleteTodoItemFn.mockReturnValue ({excluído: true}); const {getByText}=render (); fireEvent.press (getByText ("Editar")); fireEvent.press (getByText ("Del")); esperar (mockEditTodoItemFn.mock.results [0].value).toBe ({ editado: verdadeiro, }); expect (mockDeleteTodoItemFn.mock.results [0].value).toBe ({ excluído: verdadeiro, }); });
O TodoItem
renderizou dois botões com o texto Del
e Edit
. Usamos getByText
para acessar os nós desses botões e usamos o método fireEvent.press (...)
para pressionar o botão, assim como faríamos em um navegador real. Isso irá disparar o manipulador de eventos anexado ao evento onPress
do botão. Isso muda a saída renderizada e podemos testar o que acontece quando os botões são clicados.
function SearchFruit () { const [resultado, setResult]=useState ([]); const [searchItem, setSearchItem]=useState (); const frutas=["laranja","maçã","goiaba","lima","limão"]; useEffect (()=> { if (searchtiem.length> 0) { setResult (fruits.includes (searchItem)); } }, [searchItem]); Retorna ( <>setSearchItem (texto)} /> {result.map ((fruta, i)=> ( {fruit} ))} > ); }
Acima, temos um componente que pesquisa frutas em uma matriz e exibe o resultado se encontrado.
Podemos escrever testes para garantir que os manipuladores de eventos sejam disparados quando o usuário interage com eles e que os resultados corretos sejam renderizados.
it ("procurar uma fruta quando o nome da fruta for inserido/digitado", ()=> { const {getByPlaceholder}=render (); fireEvent.changeText (getByPlaceholder ("Pesquisar frutas"),"goiaba"); expect (getAllByText ("guava")). toHaveLength (1); });
Acima, estamos testando que, quando um usuário digita “goiaba”, o resultado correto é exibido, pois temos a goiaba na matriz frutas
.
O método fireEvent.changeText ()
altera o texto de uma caixa de entrada, disparando assim o manipulador de eventos onChange
. getAllByText
obtém qualquer ocorrência do texto “goiaba” no array. Como sabemos que goiaba está no array frutas
, o texto “goiaba” deve ser renderizado.
Eventos de disparo
Para disparar eventos nos componentes do React Native, usamos os métodos da API fireEvent
da biblioteca de testes do React Native.
pressione
Isso dispara o evento press
em um elemento, que chama seu manipulador anexado.
Para disparar o evento press
, a Biblioteca de testes nativos do React exporta o objeto fireEvent
e chama o método press ()
. Recebe como parâmetro a instância do elemento a ser pressionado.
const onPressMock=jest.fn (); const {getByText}=render (); fireEvent.press (getByText ("Press Me")); expect (onPressMock).toHaveBeenCalled (); Pressione-me
Definimos um evento press
no elemento TouchableOpacity
, com um manipulador de função simulado anexado ao evento. Usamos fireEvent.press ()
para “pressionar” o elemento, chamando o manipulador simulado. Esperamos que isso chame o manipulador simulado.
changeText
Este evento insere dados de texto em um elemento e dispara o evento changeText
no elemento, que chama o manipulador do elemento.
const onChangeTextMock=jest.fn (); const {getByPlaceholder}=render (); fireEvent.changeText (getByPlaceholder ("Pesquisar frutas"),"goiaba"); expect (onChangeTextMock).toHaveBeenCalled ();
Configuramos um manipulador de simulação no evento onChangeText
da caixa TextInput
. Nós disparamos o evento usando fireEvent.changeText (...)
. Agora, esperamos que o manipulador simulado seja chamado quando fireEvent.changeText (...)
for chamado na caixa TextInput
.
Mais sobre eventos na Biblioteca de testes nativos do React podem ser encontrados aqui
Conclusão
Claro, podemos dizer muito mais sobre os testes de unidade no React Native, mas isso deve colocá-lo em funcionamento.
Vimos como o Jest pode ser poderoso como uma estrutura de teste em aplicativos baseados no React, particularmente no React Native. Também vimos como a Biblioteca de testes nativos do React é incrível, com sua abundância de métodos de consulta e evento.
Se você tiver alguma dúvida sobre este tópico, ou se sentir que há algo que devo adicionar, corrigir ou remover, sinta-se à vontade para comentar, enviar um e-mail ou enviar uma mensagem automática Obrigado!
A postagem Guia para testes de unidade no React Native apareceu primeiro em LogRocket Blog .