Jump to content

Entendendo um relatório de cobertura de testes em Jest


Kevin Silva

Postagens Recomendadas

A cobertura de testes automatizados desempenha um papel crucial no desenvolvimento de software, pois avalia a extensão em que o código-fonte é testado por casos automatizados. Uma cobertura abrangente assegura que diversas partes do código sejam exercitadas, identificando possíveis falhas e melhorando a confiabilidade do sistema. Por essa razão, é importante que o desenvolvedor ou analista de qualidade que estiver implementando testes automatizados saiba não apenas gerar relatórios de cobertura, mas também entenda como essa cobertura é calculada com base no trecho de código e no teste automatizado implementado para tal trecho.

Para exemplificar como entender um relatório de cobertura de teste, será usada a ferramente Jest. Após a execução de testes de unidade/integração implementados por meio do Jest,  a ferramenta possibilita a geração de um relatório de cobertura para um ou mais desses testes. Esse relatório indica o quanto o teste implementado está de fato cobrindo os fluxos de código dos módulo/função/classe do qual ele é referente. Para determinar o nível de cobertura de um arquivo específico, o Jest apresenta uma tabela contendo 6 colunas:

image.png

  • File: Nessa coluna se encontram os nomes de todos  os arquivos Javascript que foram "chamados" enquanto ocorrem a execução dos testes implementados.
  • % Stmts:  A porcentagem de termos de  Statements ( Declarações), como variáveis, constantes e imports  presentes no arquivo que estão cobertos pelos testes.
  • % Branch: A porcentagem de Branches (Ramificações) no arquivo que estão cobertas pelo teste. Branches ou Ramificações são qualquer trecho de código que divide a execução de um programa em duas ou mais partes. Como exemplo de ramificações, temos os blocos de if/elseswitch/case ou ternários. 
  • % Funcs: A porcentagem de Funções (rotinas e sub-rotinas) do código que estão cobertas pelo teste.
  • % Lines: A porcentagem de linhas do arquivo que estão cobertas pelo teste.
  • Uncovered Lines: O oposto do item anterior. Contém os números das linhas que não foram cobertas pelo teste.

Imagine um código de programação que reproduza as funcionalidades mais básicas de uma calculadora: adição, subtração, multiplicação e divisão. Esse código se encontra em um arquivo do tipo JavaScript (chamado calculadora.js) cuja função calculadora (op, a, b) contém as funcionalidades descritas, assim como outras validações (como por exemplo, verificar se op, a e b são valores numéricos não vazios) .

const calculadora = (op, a, b) => { // calculadora.js  
  if ([op, a, b].some(val => isNaN(val))) 
    return ('a, b e op devem ser valores numéricos!')
  else if ([op, a, b].some(val => val == null || val === ''))
    return ('a, b e op não devem ser vazios')
  else 
    console.log('a, b e op são valores numéricos! OK!')

  const soma = (a, b) => a + b
  const sub = (a, b) => a - b
  const mult = (a, b) => a * b
  const div = (a, b) => a / b

  let res
  let msg

  switch (op) {
    case 1:
      res = soma(a, b);
      msg = `O valor da soma de ${a} e ${b} é igual a ${res}`;
      break;

    case 2:
      res = sub(a, b);
      msg = `O valor da subtração de ${a} e ${b} é igual a ${res}`;
      break;

    case 3:
      res = mult(a, b);
      msg = `O valor da multiplicação de ${a} e ${b} é igual a ${res}`;      
      break;

    default:
      res = div(a, b);
      msg = `O valor da divisão de ${a} e ${b} é igual a ${res}`;
    break;
  }

  return msg;
};

export default{
  calculadora
}

E para testar os fluxos do arquivo acima, foi implementado um teste em Jest chamado calculadora.test.js.

// calculadora.test.js

import { describe, expect, it, jest } from '@jest/globals';
import calculadora from '../../modulo/calculadora.js';

describe('Valida os parâmetros da função antes de realizar os cálculos', () => {
  it('Retorna se a não for um número', () => {
    const calc = calculadora.calculadora(1, 'numero', 3)

    expect(calc).toBe('a, b e op devem ser valores numéricos!')
  });

  it('Retorna se b não for um número', () => {
    const calc = calculadora.calculadora(2, 3, 'numero')

    expect(calc).toBe('a, b e op devem ser valores numéricos!')
  });

  it('Retorna se op não for um número', () => {
    const calc = calculadora.calculadora('op', 3, 1)

    expect(calc).toBe('a, b e op devem ser valores numéricos!')
  });

  it('Retorna se a for vazio', () => {
    const calc = calculadora.calculadora(1, null , 1)

    expect(calc).toBe('a, b e op não devem ser vazios')    
  })

  it('Retorna se b for vazio', () => {
    const calc = calculadora.calculadora(1, 3, null)

    expect(calc).toBe('a, b e op não devem ser vazios')
  })

  it('Retorna se op for vazio', () => {
    const calc = calculadora.calculadora('', 4, 1)

    expect(calc).toBe('a, b e op não devem ser vazios')
  })

  it('Exibe mensagem informando que a, b e op são corretos', () => {
    const consoleSpy = jest.spyOn(console, 'log');
    
    calculadora.calculadora(11, 2, 3)

    expect(consoleSpy).toHaveBeenCalledWith('a, b e op são valores numéricos! OK!')
  })
})

describe('realiza as operações de calculadora', () => {

  it('Operação de adição', () => {
    const calc = calculadora.calculadora(1, 2, 2)

    expect(calc).toBe('O valor da soma de 2 e 2 é igual a 4')
  });

  it('Operação de subtração', () => {
    const calc = calculadora.calculadora(2, 0, 3)

    expect(calc).toBe('O valor da subtração de 0 e 3 é igual a -3')
  });

  it('Operação de multiplicação', () => {
    const calc = calculadora.calculadora(3, -2, 4)

    expect(calc).toBe('O valor da multiplicação de -2 e 4 é igual a -8')
  });

  it('Operação de divisão', () => {
    const calc = calculadora.calculadora(4, -6, 2)

    expect(calc).toBe('O valor da divisão de -6 e 2 é igual a -3')
  });
})

Rode o comando abaixo para executar a suíte de testes acima e assim gerar o relatório para a mesma:

node --experimental-vm-modules node_modules/jest/bin/jest.js --detectOpenHandles --watch --coverage

O relatório com a cobertura do teste será apresentado no fim da execução. Repare que o teste acima cobre 100% de todos os fluxos do calculadora.js.

image.png

Statements e Function

Para entender um exemplo de como a cobertura de um statement é feita, no arquivo calculadora.js, se a linha 22 for comentada e logo abaixo for adicionada a seguinte declaração.

// res = soma(a, b);
res = a + b;

Observe que a operação de adição ainda é realizada e a msg indicando o valor da soma de a e b ainda será retornada. Porém a fuinção soma (a , b) não é mais utilizada. Ao rodar o teste novamente temos o resultado abaixo.

image.png

Repare que a porcentagem de statements diminuiu para 96.66%. Isso ocorreu pois a atribuição para a const soma não foi chamada em nenhum momento durante os testes, e por essa razão não está coberta pelos mesmos. Observe também que, por const soma estar recebendo uma função como atribuição, e pelo fato de soma não estar coberto, a porcentagem de funções também cai para 85.71%.

Branch,  Lines e Uncovered Lines

Agora imagine que as linhas dos testes referentes à verificar se os parâmetros do tipo número sejam comentadas:

// calculadora.test.js

import { describe, expect, it, jest } from '@jest/globals';
import calculadora from '../../modulo/calculadora.js';

describe('Valida os parâmetros da função antes de realizar os cálculos', () => {
  // it('Retorna se a não for um número', () => {
  //   const calc = calculadora.calculadora(1, 'numero', 3)

  //   expect(calc).toBe('a, b e op devem ser valores numéricos!')
  // });

  // it('Retorna se b não for um número', () => {
  //   const calc = calculadora.calculadora(2, 3, 'numero')

  //   expect(calc).toBe('a, b e op devem ser valores numéricos!')
  // });

  // it('Retorna se op não for um número', () => {
  //   const calc = calculadora.calculadora('op', 3, 1)

  //   expect(calc).toBe('a, b e op devem ser valores numéricos!')
  // });
})

Ao rodar os testes novamente, temos o resultado abaixo. A porcentagem de branch diminuiu para 90% pois a ramificação (if) da linha 2 não está mais coberto. Consequentemente, o fluxo de código que seria executado caso o resultado da condição fosse verdadeira também não está coberto, como mostra a baixa da porcentagem de linhas cobertas e a indicação da linha 3 como não coberta. E como esse fluxo de código seria um retorno de função que poderia ser atribuído para uma variável, logo a porcentagem de statement também teve uma leve queda.

image.png

Conforme dito anteriormente, é importante que programadores e profissionais de garantia de qualidade (QA) compreendam as porcentagens de cobertura, pois isso permite uma avaliação mais precisa da robustez do código. O conhecimento sobre a cobertura de testes possibilita uma abordagem mais informada na identificação de áreas críticas que necessitam de mais atenção, promovendo a eficácia do processo de desenvolvimento e garantindo a entrega de software mais estável e confiável.

 

Fontes:

 

 

Link to comment
Compartilhe em outros sites

Crie uma conta ou entre para comentar 😀

Você precisa ser um membro para deixar um comentário.

Crie a sua conta

Participe da nossa comunidade, crie sua conta.
É bem rápido!

Criar minha conta agora

Entrar

Você já tem uma conta?
Faça o login agora.

Entrar agora


×
×
  • Create New...