Jump to content

Kevin Silva

Pessoal da TecnoSpeed
  • Contagem de Conteúdo

    15
  • Ingressou

  • Última visita

  • Dias Ganhos

    3

Kevin Silva ganhou o dia em Março 1 2023

Kevin Silva teve o conteúdo mais curtido!

Informações Pessoais

  • Cidade
    Maringá
  • Estado
    Paraná (PR)

Clientes & Parceiros

  • Você é um cliente TecnoSpeed?
    Não
  • Você é um parceiro da Casa do Desenvolvedor?
    Não

Visitantes Recentes do Perfil

O bloco de visitantes recentes está desativado e não está sendo mostrado a outros usuários.

Conquistas de Kevin Silva

  • Ótima Reputação Raro
  • Positividade Raro

Emblemas Recentes

21

Reputação na Comunidade

  1. 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: Objetivos específicos Base de teste (Produtos de trabalho que podem ser usados) Objeto de teste (ou seja, o que está sendo testado) Defeitos e falhas típicas Abordagens e responsabilidades específicas 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: Reduzir o risco Verificar se os comportamentos funcional (ex: correção de cálculos) e não funcional (ex. busca de vazamentos de memória) do componente correspondem ao que foi inicialmente projetado e especificado Construir a confiança na qualidade do componente Encontrar defeitos no componente Evitar que defeitos espalhem para níveis mais altos de teste Base de teste: Projeto detalhado Código Modelo de dados Especificações de componentes Objetos de teste Componentes, unidades ou módulos Estruturas de código e dados Classes Módulos de banco de dados 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 Funcionalidade incorreta (ex: não conformidade descrita nas especificações do projeto) Problemas no fluxo de dados Código e lógica incorretos 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. O teste de integração de componentes foca nas interações e interfaces entre componentes integrados. Ele é executado após o teste de componente e geralmente é automatizado e faz parte do processo de integração contínua. Por sua vez, o teste de integração do sistema concentra-se nas interações e interfaces entre sistemas, pacotes e micro serviços e pode ser feito após o teste do sistema ou em paralelo com as atividades de teste do sistema. Também pode abranger interações e interfaces fornecidas por entidades externas (ex: serviços da Web). Nesse caso, a entidade em desenvolvimento não controla as interfaces externas e isso pode gerar vaŕios desafios para testes (ex: garantir que os defeitos de bloqueio de teste no código da organização externa estejam resolvidos, organizar ambientes de teste, etc.) Objetivos: Reduzir o risco Verificar se os comportamentos funcionais e não-funcionais das interfaces estão projetados e especificados Construir Confiança na qualidade das interfaces Encontrar defeitos (nas próprias interfaces, nos componentes ou nos sistemas) Evitar que os defeitos se espalhem para os níveis mais altos de testes Base de teste: Software e modelagem do sistema; Diagramas de sequência; Especificações de interface e protocolo de comunicação; Casos de uso; Arquitetura no nível de componente ou sistema; Fluxos de trabalho; Definições de interface externa. Objetos de teste Subsistemas Banco de dados Infraestrutura Interfaces APIs Micros serviços Defeitos típico e falhas Testes de integração de componentes: Dados incorretos, dados ausentes ou codificação de dados incorreta; Sequenciamento ou temporização incorretos de chamadas de interface; Incompatibilidade de interface; Falhas na comunicação entre componentes; Falha de comunicação não manipulada ou tratada de forma errada entre componentes; Suposições incorretas sobre o significado, as unidades ou limites dos dados que estão sendo transmitidos entre os componentes. Testes de integração de sistemas: Estruturas de mensagens inconsistentes entre sistemas; Dados incorretos, dados ausentes ou codificação de dados incorreta; Incompatibilidade de interface; Falhas na comunicação entre sistemas; Falha de comunicação não manipulada ou tratada de forma errada entre sistemas; Suposições incorretas sobre o significado, unidades ou limites dos dados que estão sendo transmitidos entre sistemas; Falha no cumprimento dos regulamentos de segurança obrigatórios. 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: Reduzir o risco Verificar se os comportamentos funcionais e não-funcionais do sistema estão como projetados e especificados Validar se o sistema está completo e funcionará como esperado Criar confiança na qualidade do sistema como um todo Encontrar defeitos e evitar que eles se espalhem para níveis mais altos de teste ou produção Base de teste: Especificações de requisitos de sistema e software (funcionais e não-funcionais) Relatórios de análise de risco Casos de uso Épicos e histórias de usuários Modelos de comportamento do sistema Diagramas de estado Sistema e manuais do usuário Objetos de teste: Aplicações Sistemas de hardware e software Sistemas operacionais Sistema sob teste (SUT) Configuração do sistema e dados de configuração Defeitos típico e falhas: Cálculos incorretos; Comportamento funcional ou não funcional do sistema incorreto ou inesperado Controle e/ou fluxos de dados dentro do sistema incorretos Falha na execução correta e completa de tarefas funcionais de ponta a ponta Falha do sistema em funcionar adequadamente no(s) ambiente(s) de produção Falha do sistema para funcionar conforme descrito nos manuais do sistema e do usuário 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: Estabelecer confiança na qualidade do sistema como um todo Validar que o sistema está completo e funcionará como esperado Verificar se os comportamentos funcionais e não-funcionais do sistema são os especificados. 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 backup e restauração Instalar, desinstalar e atualizar Recuperação de desastres Gerenciamento de usuários Tarefas de manutenção Carregamento de dados e tarefas de migração Verifica vulnerabilidades de segurança Teste de performance (suportado por ferramentas como Jmeter e Grafana K6) 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: Processos de negócios Requisitos do usuário ou de negócios Regulamentos, contratos legais e normas Casos de uso Requisitos de sistema Documentação do sistema ou usuário Procedimentos de instalação Relatórios de análise de risco Objetos de teste típicos Sistema sob teste Configuração do sistema e dados de configuração Processos de negócios para um sistema totalmente integrado Sistemas de recuperação e hot sites (para continuidade de negócios e testes de recuperação de desastres) Processos operacionais e de manutenção Formulários Relatórios Dados de produção existentes e convertidos Defeitos típico e falhas: Fluxos de trabalho do sistema não atendem aos requisitos do negócio ou do usuário Regras de negócios não são implementadas corretamente O sistema não satisfaz os requisitos contratuais ou regulatórios Falhas não-funcionais, como vulnerabilidades de segurança, eficiência de performance inadequada sob altas cargas ou operação inadequada em uma plataforma suportada 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
  2. 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: Documentação do Jest em PT-BR Post: Anatomia de um teste em javascript
  3. 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.
  4. 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.
  5. 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
  6. 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.
  7. 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:
  8. 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 👍.
  9. Boa tarde Victor, tudo bem sim e com você? Por gentileza, só confirma se você instalou todas as dependências citadas nessa parte do texto: 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?
  10. 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 https://github.com/BBE78/cypress-sonarqube-reporter
  11. Sempre bom relembrar os fundamentos de um assunto importante como OO! Top demais 👊
  12. 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.
×
×
  • Create New...