Testes Automatizados
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:
DETOX
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
-
Testes Unitários: Garante que componentes de código individuais funcionem corretamente de forma isolada.
-
Testes de Integração: Verifica se diferentes partes do sistema funcionam perfeitamente em conjunto.
-
Testes de Sistema: Avalia a conformidade de todo o sistema com os requisitos e desempenho do usuário.
-
Testes de Carga: Testa a capacidade do sistema em lidar com altas cargas de trabalho e identifica problemas de desempenho.
-
Testes de Erro: Avalia como o software lida com entradas inválidas e condições de erro.
-
Automação de Testes: Automatiza a execução dos casos de teste para eficiência, repetibilidade e redução de erros.
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.
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.
- 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.
- 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
- https://martinfowler.com/testing/
- https://martinfowler.com/articles/mocksArentStubs.html
- https://blog.cleancoder.com/uncle-bob/2014/05/14/TheLittleMocker.html
Embedded content: https://docs.google.com/presentation/d/1YHgBQ0JJ-x5mIm5jaWv_xeVDusS0YpwAPvjfQdqM_YU/edit?usp=sharing