TDD com SQL e funções de manipulação de dados

14

Enquanto sou programador profissional, nunca fui formalmente treinado em engenharia de software. Como eu frequentemente visito aqui e SO, notei uma tendência para escrever testes de unidade sempre que possível e, conforme meu software se torna mais complexo e sofisticado, vejo os testes automatizados como uma boa idéia para ajudar na depuração.

No entanto, a maior parte do meu trabalho envolve escrever SQL complexo e depois processar a saída de alguma maneira. Como você escreveria um teste para garantir que seu SQL retornasse os dados corretos, por exemplo? Então, digamos que se os dados não estavam sob seu controle (por exemplo, o de um sistema de terceiros), como você pode testar eficientemente suas rotinas de processamento sem ter que escrever manualmente grandes quantidades de dados fictícios?

A melhor solução em que posso pensar é fazer visualizações dos dados que, juntos, cobrem a maioria dos casos. Posso então associar essas visualizações ao meu SQL para ver se ele está retornando os registros corretos e processar manualmente as visualizações para ver se minhas funções etc. estão fazendo o que deveriam. Ainda assim, parece excessivo e flakey; particularmente encontrando dados para testar ...

Xophmeister
fonte

Respostas:

6

Uma regra importante para testar tudo o que está relacionado ao banco de dados é isolá-lo completamente do restante do seu aplicativo.

A arquitetura de portas e adaptadores é um bom exemplo. O banco de dados é considerado como um plug-in externo através de um adaptador para seu aplicativo. O mesmo acontece com todos os subsistemas de terceiros. Para testar como o aplicativo se comportaria e interpretaria as respostas de subsistemas de terceiros, a única maneira de saber como testar isso é stub das respostas desse subsistema individual. Não significa necessariamente que você precisaria escrever manualmente todos os objetos de dados. Você pode adotar facilmente o uso de testes orientados a dados.

Em relação ao teste de como seu aplicativo interage com o banco de dados, você pode falsificar os adaptadores de banco de dados para usar um banco de dados na memória, por exemplo.

Agora testando suas consultas ao banco de dados. Antes de tudo, todas as consultas complexas devem ser decompostas em consultas mais fáceis, simples e previsíveis. O mesmo que você faria para uma classe de gordura ou para uma função de gordura. Existem ferramentas que podem ajudá-lo a testar seu banco de dados como o Dbunit. Uma abordagem simples que às vezes adoto é usar o conceito de testes de caracterização. Então, eu colocaria o banco de dados em um estado conhecido, executaria todas as consultas que eu tiver que gravar, salve a saída em um local (arquivo, memória) e considere essa saída como a correta. As próximas execuções comparariam a saída deles com essa, então isso definitivamente me ofereceria o teste de regressão necessário. De fato, não é garantido que a primeira saída esteja correta, mas o problema de regressão pode ser resolvido dessa maneira. Se você tiver suas consultas bem decompostas, poderá testá-las individualmente em relação ao banco de dados que está em um estado conhecido.

Vadim
fonte
3

Essa é uma pergunta interessante, porque o banco de dados geralmente é a parte que é falsificada durante o teste de unidade de aplicativo. Esperamos que a lógica do mecanismo de banco de dados em si seja bem testada pelo provedor, mas é claro que as consultas, o esquema e os procedimentos armazenados são códigos que precisam ser testados e protegidos contra a regressão. Isso geralmente é deixado para testes de integração que não são TDD.

As visualizações provavelmente seriam uma maneira difícil de fazer isso, porque elas não são realmente necessárias para o teste, primeiro teste automático de luz vermelha e luz verde de um aspecto por teste preferido no TDD. Também com visualizações, você não pode escrever o teste antes do código. Uma abordagem melhor seria escrever procedimentos armazenados onde você pode adicionar lógica "assert" no procedimento (por exemplo, usando instruções "if") para testar a saída quanto a falhas. Você precisa testar apenas uma coisa em cada teste de unidade para isolar a unidade, e o método SP seria mais adequado para isso. Além disso, com os SPs, você pode executar todo o conjunto deles como scripts à medida que desenvolve o código inicial e, posteriormente, ao testar regressões ao refatorar.

Além disso, lembre-se de que os testes devem ser repetíveis e você precisará de alguns scripts para inicializar e desmontar o estado do banco de dados para garantir que o estado seja o mesmo para cada teste de unidade.

Para sua pergunta sobre dados que não estão sob seu controle, essa é uma área difícil. Acho melhor você zombar com dados falsos e testar as condições de exceção e de borda, tanto quanto possível, para testes de unidade. Caso contrário, cairá mais na categoria de teste de integração (o que também é uma boa coisa a fazer). Para testes de integração, você pode executar seus testes com dados de terceiros e gerar uma saída inicial e, para testes subsequentes (por exemplo, após refatoração), verifique se essas saídas repetem a saída conhecida inicial.

Chave na mão
fonte
Por que você não pode escrever um teste para uma exibição que ainda não foi codificada?
Jeffo
Não se você estiver usando a visualização como o mecanismo para o teste proposto pelo OP.
Turnkey
1

Em algum momento, você precisará de dados de teste. Se você estiver usando um sistema de terceiros, o esquema já foi criado, mas você precisará solucionar futuras alterações. Felizmente, você pode obter essas alterações na documentação da atualização, mas pode ser forçado a comparar as versões do banco de dados.

Os conjuntos de resultados esperados podem ser salvos em tabelas de banco de dados ou arquivos / planilhas externas. Eu já vi CHECKSUM usado ou comparação. Ao testar uma visualização / sproc, você terá uma falha, pois ela não existe. Em seguida, você cria o objeto com código suficiente para pelo menos executar (SELECT -1 como [dados incorretos];) e receberá uma falha porque não corresponde ao conjunto de resultados. Uma vez que eles correspondem, você tem seu sinal verde.

Comecei a trabalhar com os proprietários do projeto e pedir que eles simulassem relatórios em uma planilha e tentassem apresentar dados parciais para mim (você pode colocar os dados do resultado em uma tabela de teste). Houve uma certa pressão no início, mas eles perceberam que eu criaria um relatório e eles teriam que verificá-lo de qualquer maneira. Isso economizou tempo a longo prazo. Se eles desejam fazer uma solicitação de alteração, eles podem refazer a planilha. Agora eles podem responder à pergunta "Quão difícil seria adicionar ...?"

JeffO
fonte
1

Se sua plataforma de banco de dados for o SQL Server, há uma ferramenta gratuita muito boa: tSQLt .

O tSQLt é uma estrutura de teste de unidade de banco de dados para o Microsoft SQL Server. O tSQLt é compatível com o SQL Server 2005 (é necessário o service pack 2) e acima em todas as edições.

Utilizei com sucesso a implementação de testes no nível do banco de dados.

Alguns dos principais elementos que a tornam tão útil incluem:

  • Capacidade de trabalhar com tabelas e visualizações falsas, o que reduz a configuração normal envolvida
  • Os testes são executados automaticamente nas transações (facilmente reexecutáveis)
  • Suas declarações podem fazer comparações em tabelas (reais e falsas) para que você possa ver se alterou facilmente quaisquer dados
Alain King
fonte