Olá, Habr!
Meu nome é Maxim Ponomarenko e sou desenvolvedor na Sportmaster. Tenho 10 anos de experiência na área de TI. Comecei minha carreira em testes manuais, depois mudei para desenvolvimento de bancos de dados. Nos últimos 4 anos, acumulando conhecimentos adquiridos em testes e desenvolvimento, tenho trabalhado na automatização de testes a nível de SGBD.
Faço parte da equipe da Sportmaster há pouco mais de um ano e em um dos grandes projetos estou desenvolvendo testes automatizados. Em abril, eu e a equipe do Sportmaster Lab apresentamos em uma conferência em Krasnodar, minha palestra se chamava "Testes Unitários em SGBDs", e agora quero compartilhá-la com vocês. Haverá muito texto, então decidi dividir a palestra em dois posts. No primeiro, falaremos sobre autotestes e testes em geral, e no segundo, vou me aprofundar em nosso sistema de testes unitários e nos resultados de sua aplicação.
Começando com um pouco de teoria chata. O que é teste automático? É um teste realizado por meios de software, e na moderna TI está cada vez mais sendo utilizado no desenvolvimento de software. Isso se deve ao fato de que as empresas estão crescendo, seus sistemas de informação estão se expandindo e, consequentemente, o volume de funcionalidades que precisam ser testadas também aumenta. Realizar testes manuais se torna cada vez mais custoso.
Trabalhei em uma grande empresa cujos lançamentos ocorrem a cada dois meses. Nesse processo, um mês inteiro era dedicado a que uma dezena de testadores verificasse funcionalidade manualmente. Graças à automação implementada por uma pequena equipe de desenvolvedores, conseguimos reduzir o tempo de teste para 2 semanas em um ano e meio. Não apenas aumentamos a velocidade do teste, mas também melhoramos sua qualidade. Os testes automáticos são executados regularmente e sempre realizam todo o conjunto de verificações programadas, ou seja, eliminamos o fator humano.
Para a TI moderna, é característico que de um desenvolvedor se exija não apenas escrever o código do produto, mas também escrever testes unitários que validem esse código.
Mas o que fazer se o seu sistema se baseia principalmente na lógica de servidor? Não existe uma solução universal ou melhores práticas consolidadas no mercado. Normalmente, as empresas resolvem esse problema criando seu próprio sistema de testes sob medida. Este tipo de sistema de testes automatizados foi criado em nosso projeto e vou falar sobre ele em minha apresentação.

Testando a lealdade
Para começarmos, vamos falar sobre o projeto em que implementamos o sistema de testes automatizados. Nosso projeto é o sistema de fidelidade da Sportmaster (aliás, já escrevemos sobre isso em ).
Se a sua empresa é grande o suficiente, seu sistema de fidelidade terá três propriedades padrão:
- Seu sistema será de alta carga
- Seu sistema terá processos computacionais complexos
- Seu sistema será ativamente aprimorado.
Vamos por partes... No total, considerando todas as marcas da Sportmaster, temos mais de 1000 lojas na Rússia, Ucrânia, China, Cazaquistão e Bielorrússia. Nessas lojas, cerca de 300.000 compras ocorrem diariamente. Ou seja, a cada segundo, 3-4 recibos entram em nosso sistema. Naturalmente, nosso sistema de fidelidade é de alta carga. E como ele é usado ativamente, devemos garantir os mais altos padrões de qualidade, pois qualquer erro no software pode resultar em grandes perdas financeiras, de reputação e outras.
Ao mesmo tempo, mais de cem promoções diferentes estão em operação na Sportmaster. As promoções são diversas: há as relacionadas a produtos, as vinculadas ao dia da semana, as específicas de uma loja, as que dependem do valor da compra, e promoções relacionadas à quantidade de itens. Enfim, é considerável. Os clientes têm bônus e códigos promocionais que são usados nas compras. Tudo isso torna o cálculo de qualquer pedido uma tarefa bastante não trivial.
O algoritmo que implementa o processamento de pedidos é realmente horrível e complexo. E qualquer alteração nesse algoritmo é uma tarefa bastante arriscada. Às vezes, mudanças que parecem insignificantes podem levar a efeitos bem imprevisíveis. E esses processos computacionais complexos, especialmente aqueles que realizam funcionalidades críticas, são os melhores candidatos à automação. Verificar manualmente dezenas de casos semelhantes consome muito tempo. E como o ponto de entrada no processo permanece inalterado, ao descrevê-lo uma vez, é possível rapidamente gerar testes automáticos e ter confiança no funcionamento da funcionalidade.
Como nosso sistema é amplamente utilizado, os negócios desejarão algo novo de você, mantendo-se atualizados e centrados no cliente. Em nosso sistema de fidelidade, os lançamentos ocorrem a cada dois meses. Portanto, a cada dois meses, precisamos realizar um teste de regressão completo em todo o sistema. E claro, como em qualquer TI moderna, o desenvolvimento não vai direto do desenvolvedor para a produção. Ele se inicia no ambiente do desenvolvedor, em seguida, passa sequencialmente pelo ambiente de teste, de lançamento, de aceitação e só então chega à produção. No mínimo, nos ambientes de teste e de lançamento, precisamos realizar um teste de regressão completo em todo o sistema.
As propriedades descritas são padrão para praticamente qualquer sistema de fidelidade. Vamos discutir as particularidades do nosso projeto.
Tecnologicamente, 90% da lógica do nosso sistema de fidelidade é baseada em servidor e implementada no Oracle. Existe um cliente em Delphi que desempenha a função de administrador ARMs. Também temos serviços web expostos para aplicações externas (como um site). Portanto, faz bastante sentido que, se formos desenvolver um sistema de testes automatizados, faremos isso no Oracle.
O sistema de fidelidade da Sportmaster existe há mais de 7 anos e foi desenvolvido por uma equipe de especialistas... O número médio de desenvolvedores em nosso projeto durante esses 7 anos foi de 3 a 4 pessoas. No entanto, no último ano, nossa equipe cresceu muito, e agora 10 pessoas estão trabalhando no projeto. Isso significa que novos integrantes estão entrando, os quais não estão familiarizados com as tarefas, processos e arquitetura típicos. E há um risco elevado de que possamos deixar passar erros.
O projeto caracteriza-se pela ausência de testadores dedicados como funcionários fixos. Testes, sem dúvida, são realizados, mas os analistas se encarregam dos testes além de suas outras funções principais: interagir com os clientes de negócios, usuários, elucidação de requisitos do sistema, etc. e tal... Apesar do fato de que os testes são realizados com alta qualidade (é importante mencionar isso, já que algum analista pode acabar vendo este relatório), a eficácia da especialização e do foco em uma única tarefa não deve ser ignorada.
Considerando tudo isso, para aumentar a qualidade do produto entregue e reduzir os prazos de desenvolvimento, a ideia de automatizar os testes no projeto parece bastante lógica. Em diferentes estágios da existência do sistema de fidelidade, alguns desenvolvedores fizeram esforços para cobrir seu código com testes unitários. Este foi, de modo geral, um processo bastante fragmentado, onde cada um utilizava sua própria arquitetura e métodos. O que era comum para os testes unitários eram os resultados finais: os testes eram elaborados, utilizados por um tempo, armazenados em um repositório versionado de arquivos, mas em algum momento paravam de ser executados e eram esquecidos. Isso ocorria principalmente porque os testes estavam mais ligados a um executor específico do que ao projeto.
utPLSQL vem ao nosso auxílio.

Você sabe algo sobre Steven Feuerstein?
Este é um cara inteligente, que dedicou uma parte significativa de sua carreira ao trabalho com Oracle e PL/SQL, escrevendo uma quantidade considerável de trabalhos sobre o tema. Um de seus livros mais conhecidos chama-se "Oracle PL/SQL. Para Profissionais". Stephen é o criador da solução utPLSQL, que significa Unit Testing framework for Oracle PL/SQL. A solução utPLSQL foi criada em 2016, mas continua a ser desenvolvida ativamente, com novas versões lançadas. No momento da apresentação, a versão mais recente datava de 24 de março de 2019.
Mas o que é isso? É um projeto de código aberto separado. Pesa alguns megabytes, incluindo exemplos e documentação. Fisicamente, representa um esquema separado no banco de dados ORACLE com um conjunto de pacotes e tabelas para facilitar a organização de testes de unidade. A instalação leva apenas alguns segundos. Uma característica distintiva do utPLSQL é a facilidade de uso.
Globalmente, o utPLSQL representa um mecanismo para execução de testes de unidade, onde um teste de unidade refere-se a procedimentos padrão de pacotes Oracle, cuja organização corresponde a algumas regras. Além da execução, o utPLSQL mantém um registro de todos os seus testes realizados, além de contar com um sistema interno de relatórios.
Vamos analisar um exemplo de como o código de um teste de unidade implementado segundo esta metodologia se parece.

Assim, a tela exibe o código de uma especificação típica de pacote com testes de unidade. Quais são os requisitos obrigatórios? O pacote deve ter o prefixo "utp_". Todas as procedures de teste também devem ter o mesmo prefixo. O pacote deve conter obrigatoriamente duas procedures padrão: "utp_setup" e "utp_teardown". A primeira procedure é chamada antes de cada teste de unidade, enquanto a segunda é chamada após a execução.
"utp_setup", como regra, prepara nosso sistema para a execução do teste de unidade, por exemplo, criando dados de teste. "utp_teardown" — por outro lado, reverte tudo para as configurações iniciais e limpa os resultados da execução.
Aqui está um exemplo do teste unitário mais simples, que verifica a normalização do número de telefone do cliente para o padrão da nossa sistema de fidelidade. Não existem padrões obrigatórios sobre como escrever procedimentos com testes unitários. Geralmente, um método do sistema testado é chamado, e o resultado retornado por esse método é comparado com o valor de referência. É importante que a comparação entre o resultado esperado e o obtido seja feita através de métodos padrão do utPLSQL.
Um teste unitário pode conter qualquer número de verificações. Como mostrado no exemplo, fazemos quatro chamadas sequenciais ao método testado de normalização do número de telefone e, após cada chamada, avaliamos o resultado. Ao desenvolver o teste unitário, é necessário considerar que existem verificações que não afetam o sistema, enquanto outras requerem um retorno ao estado original do sistema.
Por exemplo, no teste unitário apresentado, simplesmente formatamos o número de telefone de entrada, o que não afeta o sistema de fidelidade.
Se estivermos escrevendo testes unitários para o método de criação de um novo cliente, após cada verificação um novo cliente será criado no sistema, o que pode impactar a execução subsequente do teste.

Assim é como os testes unitários são executados. Existem duas formas aceitáveis de execução: executar todos os testes unitários de um pacote específico ou executar um teste unitário específico em um pacote específico.

Aqui está um exemplo do sistema interno de relatórios. Com base nos resultados do teste unitário, o utPLSQL gera um pequeno relatório. Nele, vemos o resultado de cada verificação específica e o resultado geral da execução do teste unitário.
6 regras dos testes automatizados
Antes de começar a criar um novo sistema de testes automatizados para o sistema de fidelidade, em conjunto com a direção, definimos os princípios que nossos futuros testes automatizados devem seguir.

- Os testes automatizados devem ser eficazes e trazer benefícios. Temos desenvolvedores incríveis, sobre os quais vale a pena falar, já que alguns deles certamente verão este relatório e estão escrevendo um código excepcional. Mas mesmo o código incrível deles não é perfeito e continha, contém e conterá erros. Os testes automatizados precisam encontrar esses erros. Se não o fizerem, ou estamos escrevendo testes automatizados ruins, ou chegamos a uma área estagnada que, em princípio, não está sendo desenvolvida. Em ambos os casos, estamos fazendo algo errado e nossa abordagem é simplesmente sem sentido.
- Os testes automatizados devem ser utilizados. É sem sentido gastar muito tempo e esforço escrevendo um produto de software, organizando seu repositório e depois esquecendo dele. Os testes devem ser executados e devem ser executados com a maior regularidade possível.
- Os testes automatizados devem funcionar de forma estável. Independentemente da hora do dia, do ambiente de execução e de outras configurações do sistema, as execuções dos testes devem levar aos mesmos resultados. Geralmente, isso é garantido pelo fato de que os testes automatizados trabalham com dados de teste especiais com configurações do sistema fixas.
- Os testes automatizados devem operar a uma velocidade aceitável para o seu projeto. Esse tempo é definido individualmente para cada sistema. Alguém pode se dar ao luxo de trabalhar o dia todo, enquanto para outro pode ser crítico concluir em segundos. Que normas de velocidade alcançamos em nosso projeto, contarei mais adiante.
- O desenvolvimento de testes automatizados deve ser flexível. Não é desejável renunciar à verificação de qualquer funcionalidade simplesmente porque ainda não fizemos isso ou por outras crenças. O utPLSQL não impõe restrições ao desenvolvimento, e a Oracle, em princípio, permite implementar as mais diversas coisas. A maioria das tarefas tem solução; a questão é apenas de tempo e esforço investido.
- Desdobrabilidade. Temos vários ambientes onde os testes precisam ser executados. Em cada um desses ambientes, o dump de dados pode ser atualizado a qualquer momento. É necessário gerenciar o projeto de testes automatizados de forma que possamos realizar sua instalação total ou parcial sem problemas.
E no segundo post em alguns dias, contarei o que fizemos e quais resultados alcançamos.
Fonte: habr.com
