25%OFF no 1º ano | 50%OFF No 2º ano

Últimos dias!

Últimos dias!

00

DIAS

00

HORAS

00

MIN

00

SEG

Desmistificando testes de unidade no Vue

Desmistificando testes de unidade no Vue
Vinicios Neves
Vinicios Neves

Compartilhe

Nesse artigo vamos aprender a identificar o que precisamos testar nas aplicações VueJS.

Num cenário onde existe integração contínua e deploy contínuo, testes são muito necessários. Afinal, precisamos garantir que o código que estamos entregando funcione como o esperado e sem efeitos colaterais. Não existe um consenso sobre teste de software, alguns querem falar sobre cobrir todas as linhas de código (em inglês, coverage)... ou seja, testar 100% do que foi escrito. Enquanto outros não estão preocupados com cobertura, mas sim em garantir o comportamento. De um jeito ou de outro, o ponto em comum é sempre testar a menor parte da aplicação. E é aí que entram os testes de unidade.

Quase ninguém voaria num avião que não fosse testado, certo? E muito embora um erro cometido em nossas aplicações não seja tão grave quanto uma falha numa aeronave, mas podemos causar grandes prejuízos e isso não é bom. Teste de software é um conteúdo muito vasto, então vamos discutir neste artigo uma visão mais pragmática sobre testes de unidade (teste de unidade - unit test - é um método onde testamos as menores porções de nossa aplicação).

Banner da Black Friday da Alura com destaque para até 50% de desconto em cursos, válido até 29/11. Transforme a sua carreira com o maior desconto do ano, matricule-se já!

Uma dúvida frequente para as pessoas que começam a escrever testes para seus componentes é: "Ok, o que eu deveria testar?". No dia a dia, trabalhamos com pessoas que testam demais ou de menos e nenhum extremo costuma ser saudável. Ao testar demais (over testing) você acaba testando além dos seus componentes, como APIs do próprio Vue. E testar de menos (under testing) não vai te dar a confiança necessária para rodar uma pipeline de publicação de forma automática. Vamos, então, seguir as boas práticas e testar com qualidade e somente o que é necessário.

Para testes de componentes de UI (user interface), o mais indicado é a escrita de teste baseado nos contratos dos componentes - a API pública. E o próprio componente em si é tratado como uma caixa preta. A ideia é testar que, dado uma entrada - input - (uma prop alterada ou uma interação do usuário), temos a saída - output - esperada. Simples assim. Vamos imaginar um componente que controla a quantidade de um item num carrinho de compras:

<template>
  <div>
    <label for="qtd">Quantidade</label>
    <input type="number" v-model="quantidade">
    <button id="incrementar" @click="incrementar">+ 1</button>
    <button id="decrementar" @click="decrementar">- 1</button>
  </div>
</template>

<script>
export default {
  data() {
    return {
      quantidade: 0,
    };
  },
  methods: {
    incrementar() {
      this.quantidade += 1;
    },
    decrementar() {
      this.quantidade -= 1;
    },
  },
};
</script>

Seguindo o indicado pelo Vue Test Utils, vamos escrever testes para cobrir os cenários de interação com o usuário:

  • dado o cenário inicial, o usuário clica no botão "+"

Nesse teste, vamos montar o componente, localizar e clicar no botão de incremento, obter o value do input e testar se é o valor esperado:

import { mount } from '@vue/test-utils';
import QuantidadeCarrinho from '@/components/QuantidadeCarrinho.vue';

describe('QuantidadeCarrinho.vue', () => {
  test('aumenta a quantidade em um ao clicar no btn +', async () => {
    const wrapper = mount(QuantidadeCarrinho);
    await wrapper.find('#incrementar').trigger('click');
    const input = wrapper.find('input');
    const quantidade = input.element.value;
    expect(quantidade).toBe('1');
  });
});

Perfeito! Exatamente como o esperado. Dado que o valor inicial é zero, pedimos um único incremento e ele passa a ser um. Vamos para o próximo cenário.

  • dado o cenário inicial, o usuário altera o valor do input e em seguida clica no botão "+"
  test('após definição de um valor no input, aumenta a quantidade em um ao clicar no btn +', async () => {
    const wrapper = mount(QuantidadeCarrinho);
    const input = wrapper.find('input');
    input.setValue('5');
    await wrapper.find('#incrementar').trigger('click');
    const quantidade = input.element.value;
    expect(quantidade).toBe('6');
  });

Com o nosso segundo teste escrito, vamos rodar e ver se tudo funciona conforme o esperado:

Opa! Esse não é o comportamento esperado. Analisando nosso componente, é fácil descobrir o motivo. No método incrementar, ele faz:

    incrementar() {
      this.quantidade += 1;
    },

Quando o usuário altera o valor via input, ele passa a ser uma string. E então o JS concatena a string ao invés de fazer a soma. Vamos fazer uma pequena refatoração - Transformar a quantidade num valor inteiro antes de fazer o incremento:

    incrementar() {
      this.quantidade = parseInt(this.quantidade) + 1;
    },

Agora, de volta ao terminal para rodar os testes:

Tudo funciona conforme o esperado. Esse tipo de ajustes e pequenas refatorações são comuns no dia a dia do desenvolvimento de testes. Existe, inclusive, uma cultura de desenvolvimento guiado por testes, chamado TDD (test driven development).

Olhando a documentação oficial , uma das bibliotecas recomendadas para testes é o Vue Test Utils. O próprio Vue Test Utils não recomenda uma abordagem baseada em cobertura de linha, ou seja, garantir que cada linha de código seja testada. Ao seguir com a abordagem de cobertura de linhas de código, focamos nas implementações internas e isso pode gerar testes frágeis. É por isso que preferimos uma abordagem orientada a contratos e interfaces públicas, tratando o componente como uma caixa preta, mas garantindo que o comportamento seja exatamente o desejado, dada às interações com o usuário ou outros componentes e eventos.

Por baixo dos panos, utilizamos o Jest e o próprio Vue Test Utils. Se gostou desse conteúdo e quer saber mais sobre, aqui na Alura temos uma Formação VueJS onde vamos nos aprofundar ainda mais em todo o ecossistema do VueJS.

Vinicios Neves
Vinicios Neves

Vinicios Neves, Tech Lead e Educador, mistura código e didática há mais de uma década. Especialista em TypeScript, lidera equipes full-stack em Lisboa e inspira futuros desenvolvedores na FIAP e Alura. Com um pé no código e outro no ensino, ele prova que a verdadeira engenharia de software vai além das linhas de código. Além de, claro, ser senior em falar que depende.

Veja outros artigos sobre Front-end