React Native: indo além dos testes de snapshot
27.08
Continuando a série sobre React Native, neste artigo iremos cobrir como criar testes automatizados para nossa aplicação. Caso não esteja acompanhando, abaixo estão os links para os artigos anteriores:
No último artigo iniciamos os testes automatizados, e vimos por meio do relatório de cobertura, que há vários códigos não testados. Neste artigo iremos justamente criar os testes que faltam, e durante a criação entender melhor o que devemos testar, o que não devemos e o principal: como criar bons testes, indo além do teste de snapshot.
bottom-up
, começando pelo TeamDetails, que se encontra abaixo:
Analisando o código acima com “chapéu” de tester/usuário, identificamos os seguintes cenários de testes:
test/unit/components/TeamDetails.test.js
, com o seguinte teste inicial cobrindo o primeiro cenário:
No teste acima estamos utilizando uma fixture que foi criada em test/fixtures/teams/brazil.json
. Já o nosso teste é bem simples:
team
que vem da nossa fixture, utilizando o react-test-renderer
-u
).test/unit/components/__snapshots__/TeamDetails.test.js.snap
), se ele bate com o que você está esperando. Isso é óbvio, porém num cenário de uma grande aplicação, prazos apertados, etc infelizmente pode acontecer do desenvolvedor simplesmente confiar, e a snapshot não ter sido gerada conforme o esperado (pense que snapshot seria como você verificar no navegador o resultado, e você não verifica)snapshot
não teríamos. Note que a assertion usando o snapshot é a última, justamente porquê ela é a mais frágil, e assim se quebrar, não irá deixar de executar as outras assertions antes.
Agora que temos nosso primeiro teste de componente, é bom entendermos o que ele garante, e o que não garante:
react-test-renderer
. Mas por outro lado, ele já nos garante algumas aspectos do nosso componente, portanto faz sentido criarmos, mesmo eles sendo frágeis.
test/jestSetup.js
, com o seguinte código dentro: jest.mock('NativeAnimatedHelper');
package.json
, coloque na seção jest
, a nova configuração abaixo:"setupFiles": [ "./test/jestSetup" ]
test/unit/components/TeamDetails.test.js
da seguinte maneira:
Ao rodar, você irá notar que nossa implementação não está pronta para o cenário do team
ser undefined, para resolver isso, iremos atualizar o nosso PropTypes (que inclusive estava desatualizado), para adicionar um valor padrão:
Note que fizemos uma pequena refatoração, para não usar snake_case, no nosso código JS, utilizando a lib humps. Essa mudança foi feita tanto no teste acima e na implementação já apresentados, como no src/services/httpRequest.js
.
Agora nossos testes irão passar. Algo a ser notar nos testes, é que estamos fazendo um “teste de sanidade”, verificando que a imagem da seleção e jogadores não são apresentadas. Porquê é algo barato de se verificar, e verifica se não estamos testando errado, ou vazando o estado de um teste para outro. Note também que adicionamos os dois novos testes em um novo describe
, isso é importante para melhorar a leitura e manutenção dos testes.
Os testes são uma excelente ferramenta para criarmos soluções mais robustas, pois é barato e simples simular cenários, que manualmente seriam mais custosos. Como vimos com o cenário de não recebermos os dados da seleção, onde nossa página estava simplesmente quebrando. A solução dada foi a mais simples, mas já torna a aplicação preparada para tal cenário, e ainda temos a garantia disso através dos testes automatizados.
TeamItem
, fica da seguinte forma.
navigation
, pois é um componente nativo e não conseguimos testar usando o Jest. O importante a notar, é que estamos fazendo a assertion do parâmetros recebidos também, e não apenas se a função foi chamada – para especificar mais o teste, já que não conseguimos testar se a navegação em si ocorreufindByType
para chamar a função onPress
, que irá disparar a navegaçãoprop
item não é passada. Para corrigir atualize a defaultProps
no src/components/TeamItem.js
:
TeamItem.defaultProps = { item: {}, navigation: undefined, };Já os testes do
TeamsList
nos traz uma complicação para testar devido a nossa implementação, pois nela temos as seguintes inconveniências:
nock
, para simular o retorno da API. Em questão de teste, no fim até é bom, pois estamos fazendo um teste mais completo, de integração (mas iremos manter o teste na pasta unit
, por questões de praticidade para o artigo)TeamItem
, que utiliza o HOC withNavigation
, que não está disponível no ambiente de teste. Devido a isso teremos que testar utilizando o pacote de shallow
do react-test-renderer
(aproveito para recomendar o uso do enzyme, que é uma lib bastante utilizada para testes de componentes React, por oferecer mais recursos aos testes)nock
, a execução do componentDidMount
ainda será assíncrona, portanto, para esperar criamos uma função para esperar a execução dos métodos assíncronos no Event Loop, o asyncFlush
Se você está utilizando o código do artigo anterior, atualize onde usamos oFeita as explicações, os testes ficarão da seguinte forma:componentWillMount
, para ocomponentDidMount
, pois ocomponentWillMount
estádeprecated
no React 16.3 e será removido no 17.
Com os últimos testes criados, já garantimos a cobertura de parte do src/api/TeamsApi.js
, esse é um benefício de realizar testes de integração, ainda mais em um cenário que o que importa é justamente a integração. Uma vez que nosso componente possui uma lógica mínima.
Para encerrar, vamos testar nossos componentes que estão na pasta screens
.
Crie um novo arquivo test/unit/screens/Home.test.js
:
O teste acima é bem simples, praticamente um teste “de contrato”, garantindo que o componente TeamsList
está sendo carregado, e usando o shallow
, justamente por que essa é a única verificação que queremos fazer, não precisamos renderizar o TeamsList
, pois acabamos de fazer o teste dele.
Agora o último arquivo a ser criado do dia/noite test/unit/screens/TeamDetails.test.js
:
Nosso último teste é parecido com o teste do TeamsList
, onde precisamos tratar os cenários antes e após os dados serem carregados.
test
: "test:coverage": "jest --coverage '--collectCoverageFrom=src/**/*.js' '--collectCoverageFrom=src/**/*.jsx'",
Agora rode yarn run test:coverage
, e você verá o resultado dos testes com o relatório de cobertura (também é gerada a versão HTML em coverage/lcov-report/index.html
):
shallow
para testar o TeamsList
. E mais importante que a cobertura, foi que conseguimos identificar erros na implementação, melhorá-la e criar testes que nos ajudam a garantir o correto funcionamento da app.
Com isso finalizamos os testes da nossa aplicação. Espero que esse e o artigo anterior, tenham te ajudado a entender como testar aplicações React/React Native, e também conceitos que valem para outras stacks.
Até o próximo artigo!
O código apresentado está disponível no Github
Na Vizir Talks #32, o Assis Neto falou sobre suas impressões do Deno.JS, veja o vídeo...
💡 #aprendi é um canal interno onde os Vizires compartilham aprendizados do dia a dia...
💡 #aprendi é um canal interno onde os Vizires compartilham aprendizados do dia a dia...
💡 #aprendi é um canal interno onde os Vizires compartilham aprendizados do dia a dia...
💡 #aprendi é um canal interno onde os Vizires compartilham aprendizados do dia a dia e...