Ouvimos muito falar sobre a importância de testar nosso código. Queremos ter feedback instantâneo sobre as mudanças que fazemos e ter confiança que o código funciona como planejado, sem precisar esperar ter uma aplicação pronta que possa ser validada. Para isso ser possível, temos diferentes tipos de testes automatizados que podemos implementar na nossa aplicação. Com o Desenvolvimento Orientado a Testes, podemos até mesmo escrever o teste antes de implementar o código, definindo o que esperamos que aquele pedaço de código faça antes que ele exista.
No Desenvolvimento Ágil, testar é parte da nossa rotina como pessoas desenvolvedoras. É tão importante que, há muito tempo atrás, Mike Cohn introduziu o conceito da Pirâmide de Testes, buscando apresentar uma forma de como pensar a estratégia de testes.
Na Pirâmide de Testes, vemos mais testes unitários na base, por serem mais rápidos de desenvolver e rodar. A quantidade de testes diminui conforme vamos subindo na pirâmide, pois aumenta o esforço necessário e o tempo de execução de cada tipo de teste. Para fazer um teste de UI, por exemplo, é necessário muito mais esforço e demora mais para rodar e ter feedback. Por isso, segundo a pirâmide, devemos ter menos testes deste tipo.
Porém, como foi dito, a pirâmide é apenas uma forma de pensar a nossa estratégia de testes, e não um caminho para ser seguido ao pé da letra. Se pensarmos em como colocar em prática em aplicações que são exclusivamente front-end, pode ser que usá-la não faça sentido.
Que tipos de testes podemos usar no front-end?
Testes Unitários
É o tipo de testes que mais ouvimos falar. Podemos considerar uma unidade como sendo a menor parte de um código. Pode ser uma função, por exemplo. Quando falamos de testes unitários, estamos verificando que essa pequena parte de código faz o que deveria fazer, independente de outras unidades.
Esse tipo de teste é rápido e fácil de escrever e, por isso, é recomendo escrever muitos destes. Quanto mais partes do código conseguirmos testar com esse tipo de teste, menos vamos precisar fazer os outros tipos de testes, que são mais custosos.
Quando desenvolvemos software para o front-end, muitas vezes trabalhamos com componentes. Os testes unitários nos permitem garantir que eles funcionam como esperado de forma isolada, mas também é preciso saber se esses componentes funcionam quando utilizados de forma conjunta. Por exemplo, podemos alterar as propriedades que um componente espera receber e alterar seus testes unitários, garantindo que continua funcionando de forma isolada. Os testes unitários vão continuar passando. Porém, como saber que os outros componentes que o utilizam não vão parar de funcionar com essa mudança? Para isso, podemos precisar de outros tipos de testes.
Algumas Ferramentas: Jest, Jasmine, Mocha e Chai
Testes de Integração
Nós já sabemos que as unidades do nosso código estão funcionando corretamente de forma isolada, mas precisamos garantir que, quando uma parte se comunicar com a outra, as coisas vão funcionar como esperado.
No front-end, eu acredito que os testes de integração são ainda mais importantes, porque queremos nos certificar de que nossos componentes funcionam conforme esperado quando estão sendo usados em conjunto.
Por exemplo, se tivermos um formulário contendo vários inputs diferentes e com um botão para enviar os dados. Queremos testar que, ao preencher todos os dados corretamente e clicar no botão, veremos a mensagem de sucesso esperada. Sendo cada input e botão um componente separado, não seria suficiente testar cada um isoladamente.
Algumas Ferramentas: Jest e Cypress
Testes E2E
Os testes end-to-end vão ainda além. Com eles, testamos os componentes trabalhando de forma integrada, mas pensando na jornada do usuário.
Podemos utilizar ferramentas que automatizam ações que seriam realizadas pelo usuário em um contexto real. A aplicação é iniciada no browser, que navega para a nossa página e executa as ações que forem definidas, como clicando em botões, preenchendo campos e verificando se os resultados são conforme esperado.
É necessário investir mais esforço para escrever esses testes e eles demoram mais para rodar, porém é o tipo de teste que nos traz mais confiança, pois sabemos que a aplicação está funcionando exatamente como esperado para o fluxo que será utilizado pelo usuário. É importante ter cuidado para não testar a mesma coisa em testes diferentes, tornando esse tipo de teste ainda mais custoso.
Algumas Ferramentas: Cypress (❤️), TestCafe e Puppeteer
Testes de Snapshot
Esse tipo de teste é focado na interface. A ideia é ter certeza que, quando fizermos quaisquer alterações, ela não terá mudanças inesperadas.
Quando um teste de snapshot é criado, ele renderiza o componente, ou seja, transforma em algo que o navegador consegue entender e mostrar na tela. Em seguida, "tira uma foto" do que foi renderizado, e guarda aquela imagem. Cada vez que os testes forem rodados, o que for renderizado é comparado com a imagem que estava guardada. Se houver alguma diferença, o teste falha e sabemos que algo na nossa interface foi alterado, sem precisar rodar a aplicação inteira pra isso. Se fizemos uma alteração intencional na interface, basta atualizarmos a imagem daquele teste.
Esse tipo de teste não substitui os outros, pois tem objetivos diferentes e devem ser usados em conjunto. Os testes de snapshot ajudam a ver exatamente o que foi alterado e de uma forma bem simples.
Algumas Ferramentas: Jest
Testes de Acessibilidade
Quando escrevemos software para o front-end, é muito importante manter em mente a acessibilidade. Queremos remover barreiras que possam impedir pessoas de utilizar nossa aplicação. Existem uma série de padrões de como desenvolver software que é acessível para todas.
Nós podemos ter testes automatizados que verificam esse aspecto do nosso código. Existem diversas ferramentas que nos permitem fazer isso, verificando se não temos nenhuma violação das diretrizes de acessibilidade na web.
Algumas Ferramentas: Jest Axe e Pa11y
Verificação de Tipos Estáticos
Por mais que não seja exatamente um tipo de teste, a verificação de tipos estáticos pode ser muito útil quando trabalhamos com linguagens como Javascript. Utilizando ferramentas que trazem essa funcionalidade, podemos identificar problemas e possíveis erros antes mesmo de executar o código. Esse tipo de verificação pode tornar nosso processo de desenvolvimento mais produtivo e trazer mais confiança sobre o código.
Algumas Ferramentas: Flow e TypeScript
Existem muitos outros tipos de testes que podemos utilizar no front-end. Escolher quais tipos vamos utilizar depende do contexto do nosso projeto e do que for decidido com a equipe. O que sabemos é que a abordagem tradicional nem sempre é válida aqui, sendo necessário adaptar os tipos, e a quantidade de cada tipo, para o que faz sentido no nosso contexto.
Escreva código fácil de testar
Quando trabalhamos com um código em que há muitas dependências e em que as responsabilidades não estão bem definidas, escrever testes pode se tornar uma tarefa chata e difícil. Por isso, é importante ter em mente que queremos escrever código que seja fácil de testar.
Podemos fazer isso tendo em mente alguns princípios quando estamos desenvolvendo, como manter uma única responsabilidade para cada pedaço de código (uma função deve fazer apenas uma coisa, por exemplo), buscar ter menos dependências entre diferentes partes do código e, ainda mais relevante para o front-end, manter a lógica de negócio separada da interface da aplicação. Escrever código fácil de testar também ajuda a tornar o código mais legível, fácil de dar manutenção e de implementar funcionalidades novas.
Outra forma de fazer isso é ter o desenvolvimento sendo guiado por testes, escrevendo o teste antes mesmo de implementar o código. É o que conhecemos por TDD (Test Driven Development) e que também pode ser utilizado no front-end. Dessa forma, pensamos no comportamento que estamos esperando para aquela funcionalidade e escrevemos um teste para isso. O teste irá falhar, pois a funcionalidade ainda não existe. Logo após, implementamos o código e rodamos o teste novamente, que agora irá passar. Seguimos nesse fluxo também para fazer refatorações, garantindo que aquele pedaço de código faz somente o que é esperado dele e que está funcionando corretamente.
Legal, mas por onde eu começo?
Implementar uma aplicação com uma estratégia de testes bem pensada é ótimo na teoria, mas na prática sabemos que é muito mais complicado. Diversas vezes grande parte da aplicação já foi escrita e com quase nenhum teste. Como saber onde começar a testar as funcionalidades que já existem?
Nesse caso, acredito que faz mais sentido começar pelo fim. Podemos utilizar os testes E2E para garantir que a aplicação funciona conforme esperado pelo usuário, testando de forma automatizada os principais fluxos e garantindo que eles não irão quebrar quando fizermos alterações ou incluirmos novas funcionalidades. Depois, podemos começar a inserir os outros tipos de testes no nosso processo de desenvolvimento e aos poucos ir "equilibrando".
Independente da estratégia de testes que decidirmos seguir, o importante é começar uma conversa e estimular a cultura de testes, tendo em mente que todo o time é responsável pela qualidade.
Top comments (8)
que sensacional, parabéns.
Muito bom artigo, parabéns!
Excelente artigo!
Muito bom o artigo. Bem explicado e didático.
Super Artigo, Muito obrigado.
Show!Muito bom o artigo!
Que post maravilhoso me ajudou muita a dar o ponta pé inicial para aprender testes, você explicou de uma forma que nem fiquei com dúvidas. Obrigada! Agora vou partir para prática 👩💻
Ótimo, para testes ponta a ponta (E2E) também tem o PlayWright.