-
Contagem de Conteúdo
15 -
Ingressou
-
Última visita
-
Dias Ganhos
3
Tipo de Conteúdo
Perfis
Fóruns
Blogs
Calendário
Downloads
Postagens postado por Kevin Silva
-
-
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:
- 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/else, switch/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.
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.
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.
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:
-
Em 10/11/2023 at 14:20, hamilton_desouza disse:
Uma outra duvida: "Posteriormente, basta rodar todos os testes com o comando abaixo e se tudo foi configurado corretamente, o arquivo coverage/xml-reports/sonar.xml será gerado com sucesso. Por fim, crie o arquivo sonar.js com as seguintes informações do seu repositório para o escaneamento e envio dos dados para o SonarQube:", Qual seria o comando? o arquivo sonar.js, em qual pasta coloco?
Bom dia Hamilton, tente rodar com o comando abaixo:
npm run cypress:run
E o arquivo sonar.js deve ficar na pasta raiz do seu projeto, ao lado de arquivos como o package.json.
- 1
-
Bom dia Hamilton, tudo bem sim e com você?
Eu usei "subir a aplicação" no sentido de você precisar executar/rodar a aplicação na sua máquina para ver se o código foi instrumentalizado com sucesso.- 1
-
Nos últimos 50 anos , foram sugeridas diversas boas práticas de testes em software que ofereceram diretrizes gerais comuns que podem ser aplicadas para todos os tipos de testes existentes. Essas boas práticas foram reunidas em 7 princípios que serão abordados logo abaixo.
1. O teste mostra a presença de defeitos e não a sua ausência
Um teste reduz a probabilidade de defeitos não descobertos permanecerem no software. Entretanto, mesmo que nenhum defeito seja encontrado durante a execução do teste, isso não significa que o teste é uma prova de correção. Imagine por exemplo, um software que possua uma suíte de testes automatizados que é executada em um determinado momento e, todos os testes dessa suíte não encontraram nenhum defeito durante a execução.
O fato de todos os testes terem passado sem falhar não é uma certeza de que o software esteja livre de outros defeitos, especialmente em partes em que a suíte de testes possa não estar com a cobertura adequada.
2. Testes exaustivos são impossíveis
Testar tudo (ou seja, todas as combinações de entradas e pré-condições) não é viável, exceto em casos triviais. Ao invés de tentar testar um software exaustivamente, é mais adequado focar o tempo e o esforço na análise de risco, para decidir onde e quando começar a testar e identificar áreas do software que precisam de mais atenção.
Em adição, usar as técnicas de teste e alinhar as prioridades considerando prazos de entrega e o esforço necessário para a criação e execução dos testes também são importantes e ajudam na obtenção de um custo-benefício adequado.
3. O teste inicial economiza tempo e dinheiro
Para encontrar antecipadamente os defeitos, as atividades de teste estático e dinâmico devem iniciar o mais cedo possível no ciclo de vida de desenvolvimento de software. O teste inicial é por vezes referido como shift left. O teste no início do ciclo de vida de desenvolvimento de software ajuda a reduzir ou eliminar alterações dispendiosas.
A análise estática do código-fonte é um exemplo de teste estático, e ela pode ocorrer durante code reviews manuais ou por meio de ferramentas (Como o SonarQube, por exemplo) sem a necessidade de execução do software. Já exemplos de testes dinâmicos comumente aplicados em shift left podem envolver testes de unidade e integração.
4. Defeitos se agrupam
Após a análise dos relatórios de defeitos de um sistema, é possível que a maioria dos problemas esteja relacionada a um ou mais módulos/funcionalidades de um software. Isso seria indício de que os defeitos tendem a se agrupar nessa área específica, sugerindo a necessidade de um foco adicional de teste nessa funcionalidade.
5. Cuidado com o paradoxo do pesticida
Se os mesmos testes forem repetidos várias vezes, esses testes não encontrarão novos defeitos. Para detectar novos defeitos, os testes existentes e os dados de teste podem precisar ser atualizados e/ou novos testes precisam ser implementados. Da mesma forma que os pesticidas não são mais eficazes em matar insetos depois de um tempo, os testes não são mais eficazes em encontrar novos defeitos.
Em certos casos, como o teste de regressão automatizado, o paradoxo do pesticida tem um resultado benéfico, que é o número relativamente baixo de defeitos de regressão, impedindo que esses defeitos voltem a acontecer em produção.
6. O teste depende do contexto
Um teste pode ser feito de forma diferente em diferentes contextos. Por exemplo, um software de controle industrial de segurança crítica é testado de forma diferente de um aplicativo móvel de comércio eletrônico.
Da mesma maneira, um teste em um projeto ágil (como Scrum ou Kanban) é implementado de forma diferente de um teste em um projeto de ciclo de vida sequencial, como o Waterfall (Cascata).
7. Ausência de erros é uma ilusão
Algumas organizações esperam que os testadores possam executar todos os testes possíveis e encontrar todos os defeitos possíveis, mas os princípios 2 e 1, respectivamente, nos dizem que isso é impossível. Além disso, é uma ilusão achar que apenas encontrar e corrigir muitos defeitos assegure o sucesso de um sistema.
Encontrar e corrigir muitos defeitos não é garantia de que , Como exemplo, testar exaustivamente todos os requisitos especificados e corrigir todos os defeitos encontrados não impede a produção de um software difícil de usar e/ou que não atenda às necessidades e expectativas dos stakeholders e/ou que seja inferior em comparação com outros sistemas concorrentes.
A aplicação de todos os princípios citados acima pode garantir maior eficácia e eficiência dos esforços de testes. Eles fornecem uma estrutura robusta para a implementação e execução de testes, auxiliam na identificação de defeitos precocemente, melhoram a cobertura de teste e possibilitam a adaptação ao contexto de qualquer projeto. Quando os desenvolvedores e testadores seguem tais princípios, as empresas tendem a aprimorar a qualidade dos seus produtos, reduzir os custos e riscos e também aumentar a satisfação dos clientes.
Fonte: https://bcr.bstqb.org.br/docs/syllabus_ctfl_3.1.1br.pdf
- 1
- 2
-
Instalação e uso do K6
Primeiramente, é necessária a instalação do K6. Caso você esteja em um sistema Windows, é possível instalar por meio do instalador oficial recomendado pelo próprio K6.
Para o Fedora/CentOS, é possível instalar através dos comandos a seguir no terminal:
$ sudo dnf install https://dl.k6.io/rpm/repo.rpm $ sudo dnf install k6
Para MACOS, é possível instalar através do homebrew:
$ brew install k6
Executando o K6
Crie um arquivo chamado script.js que contenha o código do teste de carga abaixo:
// script.js import http from 'k6/http'; import { sleep } from 'k6'; export default function () { http.get('https://test.k6.io'); sleep(1); }
Nele, há uma função em que um Usuário Virtual (VU) fará uma requisição GET para a URL de testes do K6 e assim que a requisição terminar de ser executada, será aguardado 1 segundo. Para executar o teste de carga, rode o comando abaixo no terminal:
$ k6 run script.js
Se a execução ocorrer com sucesso, a seguinte mensagem aparecerá quando ela acabar com os dados de execução dos testes:
http://wiki.tecnospeed.local/uploads/images/gallery/2022-12/scaled-1680-/image-1670871773985.png
Adicionando mais VUs
Em um teste de carga no K6, a carga refere-se à quantidade de VUs que realizam uma determinada requisição ao mesmo tempo e por uma determinada duração. Dependendo do objetivo de aplicar um teste de carga no seu produto, será necessário aumentar ou diminuir a quantidade de VUs e/ou o total de tempo que esses VUs ficarão fazendo a requisição.
O K6 permite rodar o mesmo script acima mas com mais VUs e com uma duração maior já na linha de comando. No exemplo abaixo, 10 Vus farão a chamada da função definida em script.js durante 30 segundos:
$ k6 run --vus 10 --duration 30s script.js
O K6 trabalha com o conceito de usuários virtuais (VUs) que executam o seu script de teste. VUs seriam, em essência, loops de while (true) paralelos. Os scripts dos testes são feitos em JavaScript como módulos ES6, tornando possível quebrar testes grandes em partes menores que possam ser inclusive reutilizadas como desejar.
Para um teste ser executado, é preciso um init code para preparar o teste e o VU code, que faz as requisições. O init code define funções e configura as options do teste (como a duration por exemplo). Todo teste possui também uma default function que serve para definir um ponto de entrada para os VUs.
// init export default function () { // vu code: fazer as coisas aqui... }
Logo, ao invés de digitar --vus 10 e --duration 30s toda vez para o script acima, é possível definir diretamente no arquivo script.js:
import http from 'k6/http'; import { sleep } from 'k6'; export const options = { vus: 10, duration: '30s', }; export default function () { http.get('http://test.k6.io'); sleep(1); }
E assim rodar o comando sem precisar passar parâmetros de options:
$ k6 run script.js
Stages: aumentando/diminuindo VUs
É possível aumentar e diminuir o número de VUs durante a execução do teste por meio do options.stages. No exemplo abaixo, há 3 estágios. O primeiro estágio tem uma duração de 30 segundos e tem o objetivo de elevar o número de VUs para um total de 20. Ou seja, começando com 0 VUs, o K6 elevará o número de VUs gradativamente e proporcionalmente ao duration estabelecido (30s). Somente no final do duration estabelecido que haverá 20 VUs fazendo requisições. Quanto menor o target e maior a duration, mais devagar será o aumento de VUs até que se atinja o valor do target (caso esse target seja maior do que 1).
No segundo estágio, a duração é de 1m30s e o target é de 10 VUs. Logo, até que se passem 1 minuto e 30 segundos, o K6 deverá diminuir a quantidade de VUs de 20 para 10 de maneira proporcional à esse tempo estabelecido. Por fim o último estágio é para a finalização do teste e em 20 segundos, o total de usuários deve cair de 10 VUs para 0 também de maneira proporcional.
Observa-se que na linha 14, há uma função check pertencente ao próprio K6. Ela é utilizada para analisar a resposta obtida da requisição e verificar se um determinado requisito foi correspondido após a execução do teste. No caso da linha 14, está sendo verificado se o status retornado pela requisição GET foi 200 OK. Outras verificações podem ser feitas como mostra na documentação da ferramenta.
import http from 'k6/http'; import { check, sleep } from 'k6'; export const options = { stages: [ { duration: '30s', target: 20 }, { duration: '1m30s', target: 10 }, { duration: '20s', target: 0 }, ], }; export default function () { const res = http.get('https://httpbin.test.k6.io/'); check(res, { 'status was 200': (r) => r.status == 200 }); sleep(1); }
Modos de Execução
O K6 suporta 3 modos de execução de um teste de carga. Para saber mais sobre as configurações de cada modo de execução, clique em um dos links abaixo.
Local: a execução do teste acontece em uma única máquina, container ou servidor CI
$ k6 run script.js
Distribuído: a execução do teste é distribuída através de um cluster Kubernetes.
$ kubectl apply -f /path/k6-resource.yaml
Cloud: a execução dos testes acontece no K6 Cloud
$ k6 cloud script.js
Saída dos Resultados
Por padrão, o K6 exibe os resultados para o stdout. Quando um teste é executado, o K6 exibe os detalhes dos resultados e das métricas usadas. Informações adicionais sobre o uso de métricas e o resumo dos resultados após o fim do teste estão presentes na documentação.
Ao invés de exibir os resultados via stdout, é possível gerar um relatório customizado com a função handleSummary(). No fim de um teste, o K6 automaticamente sempre cria um objeto que agrega todas as estatísticas dos resultados. Com handleSummary(), o objeto será processado como um relatório customizado em um formato desejado: JSON, HTML, XML e outros. No exemplo abaixo, é utilizado a extensão K6 Reporter para converter e apresentar os resultados em um relatório no formato HTML.
// script.js import http from 'k6/http'; import { sleep } from 'k6'; import { htmlReport } from "https://raw.githubusercontent.com/benc-uk/k6-reporter/main/dist/bundle.js" export function handleSummary(data) { return { "diretorio/para/salvar/arquivo/html/do/relatorio/resultados.html": htmlReport(data), } }; export default function () { http.get('https://test.k6.io'); sleep(1); }
Ao executar o script acima e abrir o arquivo gerado resultados.html, o relatório abaixo será exibido:
Além dos relatórios personalizados e do resumo padrão do stdout, é possível também fazer o streaming em tempo real dos dados obtidos em cada métrica durante a execução do teste em arquivos JSON, CSV ou em aplicações externas como Amazon CloudWatch ou o Grafana Cloud/ Prometheus.
- 4
-
Boa tarde!
Caso o seu projeto não esteja usando Vue.js + Nuxt.js, você pode usar e definir o próprio NODE_ENV como "test". Daí no package.json você pode criar um script com essa configuração por exemplo:
"dev:test": "NODE_ENV=test comando_para_subir_a_aplicação_em_modo_dev"
Aí depois naquele trecho daria para deixar assim:
Em 05/08/2022 at 11:47, Kevin Silva disse:if (process.env.NODE_ENV == "test") { presets = [ "@babel/preset-react" ] plugins = [ "transform-class-properties", "istanbul" ] }
-
Entendi Victor,
isso, o windows.__coverage__ tem que ser feito no seu navegador mesmo. No navegador que o Cypress chama vai aparecer undefined após dar o Enter.
E o arquivo babel.config.js tem que ser criado na raiz do repositório que nem o cypress.config 👍.
-
1 hora atrás, Victor Eduardo Dias Pavesi disse:
Boa tardde. tudo bem?
eu estou com uma pequena duvida, porque não estou conseguindo instrumentalizar minha aplicação cypress....
independente do que eu faça
Eu fui até a parte em criar o babel.config.js, fiz tudo certinho, porém quando fui rodar o cypress, o window._coverage_ não deuBoa tarde Victor, tudo bem sim e com você?
Por gentileza, só confirma se você instalou todas as dependências citadas nessa parte do texto:
Em 05/08/2022 at 11:47, Kevin Silva disse:npm install -D @babel/core @babel/preset-react babel-plugin-istanbul babel-plugin-transform-class-properties
E verifica também qual a versão do seu Node e das dependências acima? Aqui no meu projeto eu usei o node 16 e as dependências instaladas com as seguintes versões:
"@babel/core": "^7.16.5", "@babel/preset-react": "^7.18.6", "babel-plugin-transform-class-properties": "^6.24.1", "babel-plugin-istanbul": "^6.1.1"
Outra coisa também, você fez a verificação do window.__coverage__ no seu navegador mesmo ou no navegador que o cypress abre para rodar os testes?
-
Instalação e uso do Cypress
Primeiramente, é necessária a instalação do Cypress no seu projeto Node.js como uma devDependency:
npm install -D Cypress
Para executar o Cypress diretamente da raiz do seu projeto, adicione os dois scripts no package.json. O primeiro abrirá a GUI do Cypress, enquanto que o segundo rodará todos os testes do projeto em modo silencioso.
{ "scripts": { "cypress:open": "cypress open", "cypress:run": "cypress run" } }
Após a adição, execute o comando abaixo definido para abrir o Cypress. Caso seja a primeira vez que esteja usando o Cypress, o Launchpad do programa será exibido para guiar as decisões de projeto e configurações de tarefas que devem ser definidas antes do primeiro código ser escrito.
npm run cypress:open
Instrumentalização do código
Para calcular a taxa de cobertura em testes E2E no Cypress, é preciso primeiramente instrumentalizar o código do projeto. A instrumentalização do código é definida como a inserção de contadores adicionais no código-fonte de um projeto antes do tempo de execução. E é por meio desses contadores que o Cypress realiza a computação das linhas do código-fonte que foram executadas durante a realização dos testes e gera o total de cobertura da aplicação.
O Cypress em si não faz a instrumentalização do código. Ela deve ser feita usando o módulo nyc ou o plugin babel-plugin-istanbul durante a transpilação do código de um projeto que use Babel. Nesse tutorial, será descrito como gerar código instrumentado com o babel-plugin-istanbul. Maiores informações sobre a instrumentalização e a cobertura de código do Cypress estão disponíveis na sua documentação.
Adicione em seu projeto as seguintes dependências:
npm install -D @babel/core @babel/preset-react babel-plugin-istanbul babel-plugin-transform-class-properties
Em seguida, crie um arquivo babel.config.js na raiz do repositório do seu projeto, com as configurações abaixo. O if é usado para garantir que o preset e os plugins necessários sejam inseridos apenas durante a fase de testes, já que não há a necessidade de instrumentalizar código em outros ambientes.
module.exports = function (api) { api.cache(true); let presets = [] let plugins = [] if (process.env.test) { presets = [ "@babel/preset-react" ] plugins = [ "transform-class-properties", "istanbul" ] } return { presets, plugins }; }
Para confirmar se o código foi instrumentalizado, suba a aplicação. Lembre-se que, para o exemplo acima é preciso definir process.env como teste.
Abra o console do navegador (do seu próprio navegador, e não o que o Cypress abre para rodar os testes), digite window.__coverage__ e aperte Enter. Caso apareçam dados como na imagem abaixo, o código do seu projeto foi instrumentalizado com sucesso 🎉
Cobertura de Código E2E
Para gerar cobertura de código durante a execução dos testes, o Cypress utiliza o plugin cypress/code-coverage. Ele faz o merge da cobertura individual obtida em cada teste, salva esse resultado combinado e utiliza o nyc para gerar relatórios em HTML com esses dados de cobertura.
Primeiramente, instale o plugin com o comando:
npm install -D @cypress/code-coverage
Adicione os códigos a seguir nos respectivos arquivos da pasta do Cypress:
// cypress/support/e2e.js import '@cypress/code-coverage/support'
// cypress/plugins/index.js module.exports = (on, config) => { require('@cypress/code-coverage/task')(on, config) return config }
Abra a GUI do Cypress e execute um dos testes do seu projeto. Se os comandos dos retângulos verdes na imagem abaixo estiverem presentes durante a execução do teste, então o plugin foi integrado corretamente e a cobertura está sendo gerada.
Quando o teste terminar de rodar, o arquivo JSON com o merge das coberturas será salvo na pasta nyc_output. É desse arquivo JSON que podem ser gerados relatórios em diversos formatos, como texto, HTML e LCOV. O plugin também salva um relatório em HTML e um arquivo LCOV com todas as informações de cobertura na pasta coverage.
Geração de Relatórios para o SonarQube
O arquivo lcov.info gerado após o termino da execução dos testes contém informações como a porcentagem de cobertura de código em todo o projeto e ele deve ser enviado via sonarscanner para o SonarQube. Porém, para o Sonar contabilizar o total de testes existentes no projeto é preciso também do TestExecutionReport, que no caso do Cypress pode ser gerado por meio da lib cypress-sonarqube-reporter.
Primeiro, instale as dependências:
npm install -D cypress-sonarqube-reporter sonarqube-scanner
Em seguida, no arquivo cypress.json defina o sonarqube-reporter como reporter e configure as reporterOptions desejadas. Nesse exemplo, os relatórios .xml de cada teste serão salvos em coverage/xml-reports/.
// cypress.json { "reporter": "cypress-sonarqube-reporter", "reporterOptions": { "overwrite": true, "preserveSpecsDir": false, "outputDir": "coverage/xml-reports/" } }
Para que todos os .xml de cada teste sejam gerados corretamente, é preciso aplicar a função SpecTitle da lib nos títulos dos describes de todos os arquivos de testes existentes no seu projeto, como no exemplo abaixo:
Observação: se por alguma razão um mesmo arquivo de teste tiver dois ou mais describes que não estejam aninhados, é preciso aplicar o SpecTitle em cada um deles para funcionar corretamente.
// File: cypress/integration/Sample.spec.js const specTitle = require("cypress-sonarqube-reporter/specTitle");
describe(specTitle("The root suite"), () => { it("Test case #1 (must pass)", () => { expect(true).to.be.true; }); describe("A sub suite", () => { it("Test case #2 (must pass)", () => { expect(true).to.be.true; }); it("Test case #3 (must fail)", () => { expect(true).to.be.false; }); }); describe("Another sub suite", () => { xit("Test case #4 (must be skipped)", () => { expect(true).to.be.false; }); it("Test case #5 (must raise an error)", () => { undefined.toString(); }); }); }); describe(specTitle("Another root suite"), () => { it("Test case #4 (must pass)", () => { expect(true).to.be.true; }); });
Em seguida é preciso fazer o merge de todos os .xml de cada teste em um arquivo .xml único, de nome sonar.xml nesse exemplo.
// cypress/plugins/index.js module.exports = (on, config) => { require('@cypress/code-coverage/task')(on, config) on('after:run', (results) => { return require('cypress-sonarqube-reporter/mergeReports')(results, { mergeFileName: "sonar.xml" }) }) return config }
Logo após, basta rodar todos os testes com o comando abaixo e se tudo foi configurado corretamente, o arquivo coverage/xml-reports/sonar.xml será gerado com sucesso.
npm run cypress:run
Agora, crie o arquivo sonar.js com as seguintes informações do seu repositório para o escaneamento e envio dos dados para o SonarQube:
const scanner = require('sonarqube-scanner') scanner( { serverUrl : 'http://sonarqube.tecnospeed.local', token : '<token gerado no SonarQube para o seu projeto>', options: { 'sonar.projectKey': '<project key do seu projeto>', 'sonar.projectName': 'nome do seu projeto', 'sonar.javascript.lcov.reportPaths': 'coverage/lcov.info', 'sonar.testExecutionReportPaths': 'coverage/xml-reports/sonar.xml', 'sonar.sources': 'src', 'sonar.tests': 'cypress/integration' } }, () => process.exit() )
Stage de testes no Pipeline do Gitlab
Adicione no .gitignore as pastas criadas pelo sonarscanner e pelas dependências do gerador de cobertura do cypress:
coverage .scannerwork .nyc_output
Agora basta adicionar o script de execução dos testes do cypress e do sonar em um pipeline de testes no gitlab:
// .gitlab-ci.yml stages: - test test: image: cypress/browsers:node16.5.0-chrome94-ff93 stage: test script: - npm set registry http://devdocker.tecnospeed.local:4873/ - npm install - npm run cypress:run after_script: - node sonar.js
Se tudo correr bem após a execução do pipeline, a página de seu projeto no SonarQube será criada/atualizada com as informações relacionadas a cobertura e total de testes, duplicidades, bugs e etc. como no exemplo da imagem abaixo:
Referências:
https://docs.cypress.io/guides/tooling/code-coverage#Using-NYC
- 5
- 3
-
Sempre bom relembrar os fundamentos de um assunto importante como OO! Top demais 👊
- 1
-
Eae Eduardo, tudo certo?
Acho que um site de e-commerce estilo Americanas, Magazine Luiza, Submarino e etc. daria um TCC bacana, se o seu orientador concordar. De tecnologias que você pode usar, acho que você pode seguir algumas que são tendência, como as que o Renan sugeriu.
Os Níveis de Teste Durante o Ciclo de Vida de Desenvolvimento de Software
em Desenvolvimento de Software
Postado
No ramo do desenvolvimento de software, os níveis de teste são grupos de atividades de teste que são organizados e gerenciados juntos e que estão relacionados com outras atividades dentro do ciclo de vida de desenvolvimento de software. Eles são categorizados em Teste de componentes (testes de unidade ou teste unitário), Teste de integração, Teste do Sistema e Teste de aceite e são caracterizados pelos seguintes atributos:
Teste de Componente
O teste de componente se concentra em componentes que são testáveis separadamente e geralmente são realizados isoladamente do resto do sistema. Dependendo do modelo de ciclo de vida de desenvolvimento de software, pode exigir objetos simulados, virtualização de serviços, estrutura, simuladores e controladores.
Objetivos:
Base de teste:
Objetos de teste
Defeitos típicos e falhas
Os defeitos geralmente são corrigidos assim que são encontrados e frequentemente sem gerenciamento formal. Entretanto, quando os desenvolvedores relatam tais defeitos, isso fornece informações importantes para análise de causa raiz e melhoria do processo
Abordagens e responsabilidades específicas
Esse teste geralmente é executado pelo desenvolvedor que escreveu o código, mas obrigatoriamente requer acesso ao código que está sendo testado. O desenvolvimento de componentes pode ser alternado com a localização e a devida correção de defeitos. Geralmente, os desenvolvedores de software escrevem e executam testes depois de codificaram um componente. Entretanto, a escrita dos testes pode anteceder a codificação de um componente, como ocorre no TDD (Test Driven Development)
Teste de Integração
O teste de integração se concentra nas interações entre componentes ou sistemas.
Objetivos:
Base de teste:
Objetos de teste
Defeitos típico e falhas
transmitidos entre os componentes.
transmitidos entre sistemas;
Abordagens e responsabilidades específicas:
No teste de integração, o foco deve ser na comunicação entre componentes ou sistemas diferentes e não nas suas funcionalidades individuais (como deveria ter sido coberto durante o teste de componentes). Testes de integração de componentes geralmente são de responsabilidade dos desenvolvedores, enquanto que os de integração de sistemas são atribuídos aos testadores (ex: analistas de qualidade). Quanto maior o escopo da integração, se torna mais difícil isolar os defeitos em um componente/sistema e por essa razão a prática de integração contínua tornou-se muito comum no desenvolvimento de software para a grande maioria das empresas.
Teste de Sistema
Já o teste de sistema se concentra no comportamento e nas capacidades de todo um sistema ou produto, geralmente considerando as execuções das tarefas de ponta a ponta (End-to-End ou E2E) do sistema e os comportamentos não-funcionais exibidos ao executar tais tarefas. Geralmente, esse tipo de teste produz informações que são usadas pelos stakeholders para tomar decisões de liberação e também podem satisfazer requisitos ou padrões legais e regulatórios.
Objetivos:
Base de teste:
Objetos de teste:
Defeitos típico e falhas:
Abordagens e responsabilidades específicas:
O teste de sistema deve focar no comportamento geral de ponta a ponta do sistema, seja esse comportamento funcional ou não. Um exemplo de teste de sistema envolve o uso de uma tabela de decisão para verificar se o comportamento funcional está de acordo com o que foi estabelecido nas regras de negócio. Esse e outros tipos de testes de sistema podem ser realizados por testadores independentes, que dessa forma conseguiriam ajudar no refinamento da história dos usuário e de requisitos de negócios que forem declarados incorretamente. Existem também ferramentas como Cypress e o Playwright, que permitem a criação de testes ponta a ponta automatizados tanto para o front-end quanto para o back-end de um sistema.
Teste de Aceite
O teste de aceite, assim como o teste de sistema, geralmente foca no comportamento e capacidade de todo um sistema ou produto. Ele pode produzir informações para avaliar a situação do sistema para implantação e uso pelo usuário final (no caso, o cliente). Os defeitos até podem ser encontrados durante o teste de aceite, mas esse nem sempre é o objetivo do teste, e encontrar uma quantidade significativa de defeitos durante o teste de aceite pode representar um grande risco de projeto. Geralmente, deseja-se comprovar, por meio do teste de aceite, se o sistema satisfaz os requisitos, os padrões legais e os padrões regulatórios.
Objetivos:
Teste de Aceite do usuário (UAT)
O UAT é focado em validar a adequação do uso do sistema pelos usuários pretendidos em um ambiente operacional real ou simulado. O objetico é comprovar que os usuários podem usar o sistema para atender às suas necessidades, atender aos requisitos e executar processos de negócios com o mínimo de dificuldade, custo e risco.
Teste de Aceite Operacional (OAT)
O OAT é um teste de aceite do sistema realizado pelas operações ou pela equipe de administração de sistemas, geralmente em um ambiente de produção (simulado). O seu objetivo principal é criar confiança de que os operadores ou administradores do sistema possam manter o sistema funcionando adequadamente para os usuários no ambiente operacional, mesmo sob condições excepcionais ou difíceis. OATs podem incluir:
Teste de Aceite Contratual e Regulatório
O teste de aceite contratual se baseia nos critérios de aceite de um contrato para desenvolver softwares específicos. Tais critérios devem ser definidos quando as partes concordam com o contrato. Já o teste de aceite regulatório é realizado em relação a quaisquer regulamentos que devem ser seguidos, como governamentais, legais ou de segurança. Ambos os tipos de testes são frequentemente realizado por usuários ou testadores independentes (no caso do regulatório, os resultados podem ser testemunhados ou auditados por agências reguladoras) e possuem o objetivo de criar a confiança de que a conformidade contratual ou regulatória foi alcançada.
Alfa teste e Beta teste
São testes usados por desenvolvedores de software comercial de prateleira (COTS) que desejam obter feedback de usuários, clientes, operadores em potencial ou existentes antes que o produto seja colocado no mercado. O alfa teste é realizado no site da organização em desenvolvimento por clientes (existentes ou em potencial), operadores ou por uma equipe de teste independente. Já o beta teste é feito por esse mesmo conjunto de usuários da alfa, mas com os testes ocorrendo nos respectivos locais de cada usuário.
O objetivo desses dois testes é construir a confiança entre os clientes ou operadores de que o sistema pode ser usado no dia a dia para atingir suas metas sem o mínimo de dificuldade, custo e risco. Outro fator pode ser a detecção dos defeitos relacionados às condições e ambientes em que o sistema será utilizado, principalmente quando tais condições são difíceis de replicar pela equipe de desenvolvimento.
Base de teste:
Objetos de teste típicos
Defeitos típico e falhas:
Abordagens e responsabilidades específicas:
O teste de aceite é geralmente responsabilidade dos clientes, usuários de negócios, proprietários de produtos ou operadores de um sistema, além de stakeholders que também podem estar envolvidos.
Normalmente, ele é realizado no final, como o último nível de teste em software. No desenvolvimento iterativo, as equipes de projeto podem empregar várias formas de testes de aceite durante e ao final de cada iteração. Além disso, o alfa e o beta testes, assim como o UAT, OAT e o teste de aceite contratual e regulatório podem ocorrer no final de cada iteração, após a conclusão de cada iteração ou após uma série de iterações.
Fonte: International Software Testing Qualifications Board: Certified Testes Foundation Level Syllabus