• Nenhum resultado encontrado

Banco de Dados

No documento Padrões de testes automatizados (páginas 137-141)

Para verificar a correção da camada de persistência com banco de dados pode ser necessário tanto testes de unidade como de integração. Basicamente, a escolha do tipo de teste depende do que se está querendo verificar, mas a regra geral é utilizar os testes de unidade sempre que possível e fazer testes de integração para completar a bateria de verificações.

Entretanto, antes de definir os tipos de testes, é necessário entender o que é interessante de ser veri- ficado. A camada de persistência de dados pode ter diversos trechos de código suscetíveis a erros, além de que os tipos de erros podem variar de acordo com os arcabouços utilizados. Por exemplo, sistemas que possuem queries hardcoded no código-fonte são muito suscetíveis a erros sintáticos. Já para os sistemas que utilizam arcabouços de ORM1, são comuns problemas de desempenho, inconsistência de

dados causados por refatorações etc.

No caso de sistemas integrados com arcabouços ORM, algumas funcionalidades podem ser verifi- cadas com testes de unidade. Tanto as verificações de sintaxe quanto as de lógica da aplicação podem ser isoladas. Além disso, alguns arcabouços disponibilizam bibliotecas específicas com Objetos Dublês e métodos de verificação para facilitar a criação de testes automatizados de unidade para testar o mapea- mento dos objetos para a camada de persistência.

Já para verificar a semântica de queries, é imprescindível que os testes sejam integrados, pois elas precisam ser interpretadas pelos gerenciadores de banco de dados. Além disso, para testar uma query é preciso observar os efeitos colaterais causados na base de dados, ou seja, o teste verifica justamente a integração das funcionalidades à camada de persistência.

Contudo, é importante notar que existem diversos arcabouços que geram algumas queries auto- maticamente. Estas não precisam ser verificadas, pois é responsabilidade da equipe que desenvolveu o arcabouço avaliar se elas estão sendo geradas corretamente. Assim como para todos os tipos de testes de todas as camadas, deve-se testar apenas o sistema de interesse, dispensando as suas dependências. Uma situação excepcional é quando há interesse em verificar o comportamento do sistema sob a ação de erros conhecidos dos arcabouços.

Não obstante, a camada de persistência possui diversas particularidades que podem trazer dificul- dades para automação de testes. Entre elas estão o compartilhamento de dados, sistema de conexões de usuários, níveis e permissões de acesso, replicação da bases de dados e auditoria. No decorrer desta seção serão discutidas algumas práticas e padrões para criar testes automatizados robustos para camadas de persistência com banco de dados.

7.1.1 Configuração do Ambiente de Teste

Os testes de unidade da camada de persistência são semelhantes aos de outras camadas. Sendo assim, as dependências devem ser substituídas sempre que possível por Objetos Dublês para que os testes sejam isolados. Já os testes de integração dependem da configuração e execução correta dos ambientes e dos gerenciadores de banco de dados necessários. Todavia, a forma de organização do ambiente reflete diretamente na eficácia e na produtividade dos testes automatizados, por isso é importante conhecer as abordagens de configuração do ambiente.

Bancos de Dados Compartilhados

É comum que empresas possuam um ou mais ambientes próprios para realização de testes (geralmente manuais), que são normalmente conhecidos como ambientes de desenvolvimento, de homologação ou de garantia de qualidade. Estes ambientes são idealmente semelhantes ao de produção e úteis para a realização de testes que integram todos os módulos do sistema e suas dependências. Como estes ambientes geralmente são de alto custo, vários departamentos e projetos acabam compartilhando os recursos e as bases de dados.

Uma das principais vantagens desse ambiente para realização de testes é que ele é próximo do real, o que dá maior credibilidade às verificações e possibilita a criação de cenários de testes fiéis aos comportamentos de usuários reais. Os testes realizados nesse ambiente também são úteis para evitar e identificar problemas de instalação, configuração e de portabilidade, que são aqueles que podem ser associados à frase: “Mas no meu ambiente funcionava!”.

Outra vantagem é que a base de dados é normalmente importada do ambiente real de produção, o que permite que os testes sejam feitos com dados reais de usuários. Além disso, o uso dos dados já existentes pode facilitar a criação dos testes, pois dispensa parte da tarefa de preparar os dados para execução dos testes. A criação do set up dos testes que envolvem banco de dados exigem, via de regra, um trabalho árduo de implementação, principalmente quando a modelagem do banco é muito complexa.

No entanto, é necessário um esforço para pesquisa e avaliação dos dados antes que eles sejam utiliza- dos para os testes, o que pode ser mais custoso do que a criação de novos dados. Além disso, dificilmente os dados pesquisados poderão ser reutilizados no futuro, já que tanto os próprios testes quanto outras pessoas podem modificar os dados.

Não obstante, mesmo com as outras vantagens citadas, esse tipo de ambiente deve ser evitado para grandes baterias de testes, sejam eles automatizados ou manuais. Ambientes compartilhados trazem in- úmeras dificuldades ao processo de criação, manutenção e execução dos testes, tornando a produtividade muito baixa.

Uma das dificuldades deve-se à preocupação aos dados já existentes e aos criados pelos casos de teste. É necessário um esforço adicional para organizar e controlar os ambientes e as equipes para que a base de dados não seja degradada com a utilização. Mesmo assim, é muito difícil manter o ambiente estável por muito tempo, pois muitos testes precisam criar cenários críticos. Por exemplo, podem exigir mudanças de configuração, geração de dados inválidos para testes, base de dados vazia, entre outras.

Outro problema difícil de resolver é a execução concorrente de testes em um ambiente compartil- hado, sejam eles testes de um mesmo projeto ou de projetos diferentes. Os testes não possuem o conceito de transação, dessa forma, os comandos são executados no gerenciador de banco de dados de forma in- determinada. Isso resulta em testes intermitentes e erros difíceis de depurar. Para ilustrar, enquanto um teste pode estar inserindo dados para verificação, outro pode estar limpando a base para preparar o ambiente.

Ainda, a produtividade da verificação do sistema em teste também é prejudicada devido à redução do desempenho dos testes. A memória e o poder de processamento do ambiente são compartilhados entre diversos usuários que podem estar realizando operações demoradas e que exigem muitos recursos. Além disso, à medida que os testes vão deixando resíduos de dados na base, as queries de busca vão se tornando cada vez mais lentas.

Por estas características, a relação custo/benefício de se automatizar os testes nesse tipo de ambiente não é vantajoso. O código dos testes tende a ficar mais extenso e complexo para que eles fiquem mais robustos. Ainda assim, os testes são mais sucestíveis a serem frágeis, lentos e intermitentes do que se forem executados em outros tipos de ambientes, como veremos nas próximas subseções.

De qualquer maneira, esses ambientes são úteis para garantir a qualidade dos sistemas de software. Eles podem ser utilizados para buscar apenas erros mais específicos, a partir de testes de fumaça, de sanidade, de instalação e de configuração. Dessa forma, apenas uma pequena parcela de todas as verifi- cações são feitas nesse ambiente, o que facilita a organização e a manutenção dos testes e do ambiente. Dependendo do tamanho da bateria dos testes e de outras características, pode até ser mais vantajoso não os automatizar.

Bancos de Dados Locais

Banco de Dados Local é a configuração em que os gerenciadores de banco de dados para testes são instalados nas máquinas de cada membro da equipe de desenvolvimento. Dessa forma, cada bateria de testes de cada membro da equipe pode ser executada paralelamente, sem grandes preocupações, pois os recursos do ambiente e os dados não são compartilhados. Vale notar que a base de dados ainda é compartilhada para mesma bateria de casos de testes, por isso os testes de uma mesma bateria não de- vem ser executados paralelamente, a não ser que sejam implementados de uma maneira completamente independente dos demais.

As vantagens e desvantagens desse tipo de configuração são praticamente opostas às de ambientes compartilhados, o que torna as duas opções complementares para verificação da qualidade dos sistemas de software. As configurações de hardware e software das máquinas de desenvolvimento podem apre- sentar grandes diferenças em relação ao ambiente de produção, no entanto, cada desenvolvedor tem total autonomia para criação de diferentes cenários de teste.

A preparação dos dados para os testes é feita em métodos de set up ou nos próprios métodos de teste, ou seja, há maior autonomia, controle e flexibilidade sobre os dados criados. Além disso, os registros nas tabelas da base de dados podem ser criados de forma abstrata, com a ajuda das próprias funcionalidades do sistema, o que facilita a criação dos cenários de teste.

O desempenho das baterias de testes também pode ser significativamente melhor com bancos de dados locais do que com ambientes compartilhados. Apesar de as máquinas de desenvolvimento não terem todo o potencial de processamento daquelas de servidores, elas são normalmente utilizadas por apenas um usuário. Outro aspecto importante do desempenho deve-se à menor quantidade de dados, já que apenas um usuário de um projeto insere dados na base. Por último, bancos de dados locais dispensam a comunicação entre máquinas, que pode até ser o principal gargalo de desempenho de muitos ambientes. Contudo, o sucesso deste tipo de ambiente depende da configuração e organização dos repositórios de código-fonte. Como os bancos de dados são locais, cada desenvolvedor ou testador pode possuir con- figurações que são específicas de sua máquina, como o diretório de instalação do banco de dados. Para isso, existem duas soluções simples: ou selecionar alguns arquivos que serão ignorados durante a sin- cronização com o repositório, ou, então, utilizar endereços de arquivos relativos e outras configurações dinâmicas, ou seja, que não estejam hard coded.

Para finalizar, esse tipo de configuração de ambiente de teste também pode ser de alto custo se for necessário comprar licenças do gerenciador de banco de dados para cada máquina de desenvolvimento. Contudo, este problema pode ser facilmente resolvido se as máquinas de desenvolvimento utilizarem bancos de dados livres para realização dos testes. Entretanto, é fundamental que, em algum momento, as baterias de testes sejam executadas sobre o gerenciadores de banco de dados utilizados em ambiente de produção, o que pode ser feito idealmente no ambiente de integração contínua.

Bancos de Dados em Memória

Bancos de Dados em Memória utilizam, a priori, a memória principal do computador em vez dos discos de armazenamento. Por isso, este tipo de banco de dados é intrinsecamente mais rápido para pequenas quantidade de dados do que os tradicinais, que utilizam principalmente os discos de armazenamento.

Dessa forma, eles podem ser utilizados como banco de dados locais para o ambiente de testes. Além de todas as vantagens já descritas na subseção anterior, as baterias de testes podem tornar-se significativamente mais rápidas.

O principal obstáculo para utilizar este tipo de ambiente de testes são as grandes diferenças em relação aos bancos de dados de produção, que geralmente utilizam bancos de dados tradicionais. Por exemplo, nem todos os bancos de dados em memória oferecem triggers e stored procedures, o que pode impossibilitar os testes de vários módulos do sistema.

Mesmo assim, o recomendado é utilizar os bancos de dados em memória sempre que eles permitirem a realização de uma grande parcela dos cenários de testes necessários. No entanto, é fundamental que em algum momento seja executada a bateria de testes no ambiente real de produção para evitar erros de incompatibilidade. O mais indicado é configurar o ambiente de integração contínua [52] o mais próximo do real, para confirmar que os resultados dos testes realizados durante o desenvolvimento são confiáveis. É importante observar que mesmo com banco de dados em memória ainda é necessário cuidados para executar os testes em paralelo. Se for necessário paralelizar os testes, uma possível solução é criar uma instância distinta de banco de dados para cada caso de teste (Padrão Uma Instância de Banco de Dados por Linha de Execução, Seção 7.2.1).

No documento Padrões de testes automatizados (páginas 137-141)