Abílio Azevedo.

Testes Automatizados

Cover Image for Testes Automatizados
Abílio Azevedo
Abílio Azevedo

FIRST - Princípios do Teste Automatizado

  • Fast: Os testes devem ser executados rapidamente para prover feedback rápido.
  • Independent: Os testes devem ser isolados e não depender uns dos outros para executar.
  • Repeatable: Os testes devem produzir o mesmo resultado toda vez que forem executados.
  • Self-Validating: Os testes devem ter asserts claros que validam o comportamento esperado.
  • Timely: Os testes devem ser escritos logo no início do desenvolvimento, seguindo TDD.

Padrões de Teste - Teste Dublê

Um test double é um padrão que tem o objetivo de substituir um DOC (depended-on component) em um determinado tipo de teste por motivos de performance ou segurança. EX: Deve fazer um pedido com 3 itens em dólares Dado um novo pedido com 3 itens associados, um Livro de $50,00, um CD de $20,00 e um DVD de $30,00 Quando o pedido for realizado Então deve ser retornado uma confirmação do pedido contendo o código, juntamente com o total do pedido de R$550,00, se a cotação do dólar for R$5,50 e o status aguardando pagamento.

Dummy - Objetos usados para preencher parâmetros de métodos mas que não são utilizados.

function createOrder(user, items, dummy) {
  // dummy não é utilizado
  // código que cria o pedido
}

test('creat order', () => {
  const dummy = {}; 
  createOrder(user, items, dummy);
});

Stub - Provê respostas pré-definidas para isolamento de comportamento.

const currencyService = {
  getDollarQuote: () => 5.5  
};

function createOrder(items, currencyService) {
  // usa o stub para cotação do dólar
}

test('create order', () => {
  createOrder(items, currencyService); 
});

Spy - Captura e registra informações sobre chamadas de métodos.

const emailService = {
  sendOrderConfirmation: jest.fn()  
};

function createOrder(items, emailService) {
  // chama o spy para verificar
  emailService.sendOrderConfirmation(); 
}

test('create order', () => {
  createOrder(items, emailService);
  expect(emailService.sendOrderConfirmation).toHaveBeenCalled();
});

Mock - Pré-programa comportamentos e valida se ocorreram como esperado.

const paymentService = {
  charge: jest.fn().mockResolvedValue('PAYMENT_OK')
};

function createOrder(items, paymentService) {
  return paymentService.charge(); 
}

test('create order', async () => {
  const result = await createOrder(items, paymentService);
  expect(result).toBe('PAYMENT_OK');
});

Fake - Implementações simuladas que emulam o comportamento real.

class FakeDatabase {
  constructor() {
    this.orders = [];  
  }

  addOrder(order) {
    this.orders.push(order);
  }
}

function persistOrder(order, database) {
  database.addOrder(order);
}

test('persist order', () => {
  const database = new FakeDatabase();
  persistOrder(order, database);  
  expect(database.orders).toContainEqual(order);
});

Tipos de Teste

Unitários

Testa unidades menores de código de forma isolada.

Ferramentas:

Integração

Testa a integração entre módulos e camadas da aplicação request -> routes-> controller -> repository -> controller -> response

Testes de integração estreitos

  • Exercitam apenas a parte do código no meu serviço que se comunica com um serviço separado
  • Usam stubs/mocks desses serviços, tanto no mesmo processo ou remotamente consistem em vários testes de escopo estreito, geralmente não maiores em - - - Escopo do que um teste unitário (e geralmente executados com o mesmo framework de testes usados para testes unitários)

Testes de integração amplos

  • Requerem versões reais de todos os serviços, exigindo um ambiente de teste substancial e acesso à rede;
  • Exercitam caminhos de código através de todos os serviços, não apenas o código responsável pelas interações;

Ferramentas: As mesmas de testes unitários

Ponta-a-Ponta (E2E)

Simula o fluxo completo da aplicação do usuário.

Ferramentas:

Testes A/B

Testes A/B (também conhecidos como testes split) é uma forma de comparar duas versões de uma aplicação ou página web para ver qual tem melhor desempenho. O objetivo é melhorar métricas chave como taxas de conversão, engajamento, etc.

Durante um teste A/B, a versão original (A) e uma nova variante (B) são mostradas para diferentes segmentos de usuários. As interações e comportamentos com cada versão são medidos e uma análise estatística é usada para determinar se B tem melhor desempenho que A.

Como funciona:

  • Identifique uma métrica chave para otimizar (por exemplo, inscrições, compras)
  • Crie uma variante (B) para testar contra a original (A)
  • Mostre A e B para diferentes grupos de usuários
  • Colete dados e compare as métricas entre A e B
  • Determine se deve manter, descartar ou executar outra iteração de B

Testes A/B são comumente usados para testar alterações como diferentes designs de UI, layouts de página, botões de chamada para ação, linhas de assunto de e-mails e mais.

Ferramentas:

Técnicas de Teste

  • Caixa-branca - Baseado no código fonte, observa fluxo de dados internos
  • Caixa-preta - Baseado em requisitos, testa a aplicação pelo ponto de vista do usuário
  • Regressão - Re-executa testes para detectar erros após mudanças
  • Usabilidade - Testa experiência e comportamento do ponto de vista do usuário

Aqui está a tradução para o português:

Sistemas de Teste

  1. Testes Unitários: Garante que componentes de código individuais funcionem corretamente de forma isolada.

  2. Testes de Integração: Verifica se diferentes partes do sistema funcionam perfeitamente em conjunto.

  3. Testes de Sistema: Avalia a conformidade de todo o sistema com os requisitos e desempenho do usuário.

  4. Testes de Carga: Testa a capacidade do sistema em lidar com altas cargas de trabalho e identifica problemas de desempenho.

  5. Testes de Erro: Avalia como o software lida com entradas inválidas e condições de erro.

  6. Automação de Testes: Automatiza a execução dos casos de teste para eficiência, repetibilidade e redução de erros.

Automated Test

Testando APIs

- Testes de Fumaça

Isso é feito após o desenvolvimento da API estar completo. Apenas valida se as APIs estão funcionando e nada quebra.

- Testes Funcionais

Isso cria um plano de testes baseado nos requisitos funcionais e compara os resultados com os resultados esperados.

- Testes de Integração

Esse teste combina várias chamadas de API para executar testes de ponta a ponta. As comunicações intra-serviço e transmissões de dados são testadas.

- Testes de Regressão

Esse teste garante que correções de bugs ou novos recursos não devem quebrar os comportamentos existentes das APIs.

- Testes de Carga

Esses testes avaliam o desempenho dos aplicativos simulando diferentes cargas. Então, podemos calcular a capacidade do aplicativo.

- Testes de Estresse

Criamos deliberadamente altas cargas nas APIs e testamos se as APIs são capazes de funcionar normalmente.

- Testes de Segurança

Esse teste verifica se as APIs estão protegidas contra todas as possíveis ameaças externas.

- Testes de UI

Esse teste verifica as interações de UI com as APIs para garantir que os dados possam ser exibidos corretamente.

- Testes de Fuzz

Isso injeta dados de entrada inválidos ou inesperados na API e tenta derrubar a API. Dessa forma, identifica as vulnerabilidades da API.

API Tests

Testes de carga

Os testes de carga são uma parte importante para validar o desempenho e confiabilidade de APIs sob cargas pesadas de uso.

Definir requisitos é crucial para testes de carga efetivos. Considere a carga de trabalho esperada em produção e métricas alvo como throughput máximo, usuários simultâneos e tempos de resposta aceitáveis.

Determine as APIs e cenários a serem testados. Priorize jornadas de usuário críticas e endpoints de alto tráfego. Delimite os conjuntos de dados para uso em parâmetros e corpos de solicitação para simular dados reais.

  • Bombardier é uma ferramenta de CLI simples para realizar testes de carga bombardeando uma API com solicitações. Ele pode simular muitas conexões simultâneas para testar throughput. O Bombardier é rápido e fácil de configurar para testes de carga básicos.

Bombardier

  • O Grafana K6 eleva os testes de carga a outro nível para cenários complexos. Você pode escrever scripts usando JavaScript para definir cenários de teste flexíveis. O K6 pode simular milhares de usuários virtuais com comportamentos reais de navegador. A integração Grafana fornece visualização e monitoramento.

GrafanaK6

  • O JMeter permite gravar cenários, parametrização, assertions para validar respostas e relatórios detalhados. O ecossistema de plugins fornece muitas extensões.

Aqui estão alguns parâmetros importantes para testes de carga:

  • VU (Virtual Users) - Número de usuários simulados que estarão acessando a aplicação ao mesmo tempo. Quantos mais VUs, maior a carga.

  • Ramp-up - Tempo necessário para aumentar o número de VUs até o nível desejado. Um ramp-up lento é mais realista.

  • Duração - Tempo que o teste irá rodar na carga máxima. Quanto maior a duração, mais confiável será o teste.

  • Throughput - Taxa de transferência de requisições com sucesso. Mesmo com alta carga, o throughput não deve cair drasticamente.

  • Latência - Tempo de resposta da aplicação. A latência deve se manter baixa e estável.

  • Erros - Taxa de requisições com erro. Erros não devem aumentar com a carga.

  • Concorrência - Número de usuários acessando a aplicação ao mesmo tempo. Testes devem chegar perto da concorrência máxima suportada.

  • Rampa down - Tempo para diminuir a carga após os testes.

Monitorar esses parâmetros durante os testes de carga é essencial para avaliar o comportamento e escalabilidade da aplicação.

Dicas para testes

Não importa qual framework você use, as seguintes dicas ajudarão você a escrever melhores componentes de UI, mais testáveis, legíveis e componíveis:

  • Dê preferência a componentes puros para código de UI: dado os mesmos props, sempre renderiza o mesmo componente. Se você precisa de estado do app, pode encapsular esses componentes puros em um componente container que gerencia estado e efeitos colaterais.
  • Isole a lógica de negócios/regras de negócio em funções puras reducers.
  • Isole efeitos colaterais usando componentes container.

Mantenha esses buckets isolados:

  • Componentes de Display/UI
  • Lógica de Programa/Regras de Negócio - as coisas que lidam com o problema que você está resolvendo para o usuário.
  • Efeitos Colaterais (E/S, rede, disco, etc.)

Referências

Embedded content: https://docs.google.com/presentation/d/1YHgBQ0JJ-x5mIm5jaWv_xeVDusS0YpwAPvjfQdqM_YU/edit?usp=sharing


Mais posts

Cover Image for Documentos Técnicos

Documentos Técnicos

Aprenda a importância vital da documentação técnica abrangente para projetos de software em crescimento. Descubra as melhores práticas, como Requests for Comments (RFCs) e Architectural Decision Records (ADRs), que promovem transparência, colaboração e registro de decisões arquiteturais. Explore ferramentas poderosas como wiki.js e Backstage para criar centros de documentação eficazes. Mantenha seu projeto organizado, compreensível e sustentável com essa abordagem à documentação técnica.

Abílio Azevedo
Abílio Azevedo
Cover Image for Superlógica - BFF para o Gruvi

Superlógica - BFF para o Gruvi

Construindo um BFF (Backend for Frontend) para o SuperApp Gruvi que tem mais de 120 mil usuários ativos e milhões de possíveis usuários para disponibilizar no ecossistema Superlogica.

Abílio Azevedo
Abílio Azevedo

NewsLetter

Eu enviarei o conteúdo postado aqui no blog. Sem Spam =)

Engenheiro de software experiente, formado em Engenharia Elétrica, com mais de 10 anos de experiência prática na construção de aplicativos móveis, web e back-end robustos e escaláveis em vários projetos, principalmente no setor de fintech. Mobile (React Native), Web (React e Next.JS) e Backend (Node.JS, PHP e DJANGO). Meu objetivo é criar produtos que agreguem valor às pessoas. - © 2024, Abílio Azevedo