Teste de unidade de procedimentos armazenados

44

Estou pensando nisso há muito tempo.

A questão básica é: como testar os procedimentos armazenados de unidade?

Vejo que posso configurar testes de unidade com relativa facilidade para funções no sentido clássico (quero dizer, elas recebem zero ou mais argumentos e retornam um valor). Mas se eu considerar um exemplo da vida real de um procedimento aparentemente simples, inserindo uma linha em algum lugar, com alguns gatilhos fazendo isso e aquilo antes ou depois da inserção, é muito difícil definir os limites de uma 'unidade'. Devo testar apenas o INSERTpróprio? Isso é bastante direto, eu acho - com valor relativamente baixo. Devo testar o resultado de toda a cadeia de eventos? Além da questão de se tratar ou não de um teste de unidade, projetar um teste adequado pode ser um trabalho árduo, com muitos pontos de interrogação adicionais surgindo no caminho.

E então surge o problema de alterar constantemente os dados. No caso de UPDATEafetar mais do que apenas algumas linhas, todas as linhas potencialmente afetadas devem ser incluídas de alguma forma nos casos de teste. Dificuldades adicionais com DELETEs e assim por diante.

Então, como você testa seus procedimentos armazenados? Existe um limite de complexidade em que ele fica completamente sem esperança? Quais recursos são necessários para manutenção?

EDIT Mais uma pergunta pequena, baseada na resposta de AlexKuznetsov: Ou existe um limite sob o qual é completamente inútil?

dezso
fonte

Respostas:

32

Fazemos isso há quase cinco anos, e achamos que testar explicitamente as modificações é definitivamente factível, mas é bastante lento. Além disso, não podemos executar facilmente esses testes simultaneamente de várias conexões, a menos que utilizemos bancos de dados separados. Em vez disso, devemos testar implicitamente as modificações - usamos-as para criar pelo menos alguns dos dados de teste e verificar se nossas seleções retornam os resultados esperados.

Escrevi um artigo intitulado Feche essas brechas: lições aprendidas com o teste de unidade T-SQL , bem como algumas postagens do blog

Com relação à sua pergunta "Existe um limite de complexidade onde ele fica completamente sem esperança?", Os módulos complexos precisam de testes muito mais que os simples.

Para simplificar a manutenção, geramos os resultados esperados e os armazenamos em arquivos separados - isso faz uma enorme diferença.

AK
fonte
15

Sim, você deve testar toda a cadeia de eventos como uma unidade. Portanto, no seu exemplo com um procedimento que é inserido em uma tabela e causa acionamento de vários gatilhos, você deve escrever testes de unidade que avaliam o procedimento para várias entradas. Cada teste de unidade deve ser aprovado ou reprovado, dependendo se ele retorna os valores corretos, altera o estado das tabelas corretamente, cria o email correto e até envia os pacotes de rede corretos, se ele foi projetado para fazer isso. Em resumo, todos os efeitos da unidade devem ser verificados.

Você está certo, que o projeto de testes de unidade exige algum trabalho, mas a maior parte desse trabalho precisa ser feita para testar manualmente a unidade, você está apenas salvando o trabalho necessário para testar a unidade, para que, quando uma alteração for feita no futuro, o teste pode ser tão completo e significativamente mais fácil.

A alteração dos dados torna o teste mais difícil, mas não torna o teste menos importante e, na verdade, aumenta o valor do teste de unidade, pois a maioria das dificuldades só precisa ser pensada uma vez, e não sempre que uma alteração é feita na unidade. Conjuntos de dados salvos, inserções / atualizações / exclusões que fazem parte da configuração / desmontagem e operação com escopo restrito podem ser usados ​​para facilitar isso. Como a pergunta não é específica do banco de dados, os detalhes variam.

Não há limite de complexidade na extremidade alta ou baixa que o impeça de realizar testes ou testes de unidade. Considere estas perguntas:

  1. Você sempre escreve código sem erros?
  2. As pequenas unidades estão sempre livres de bugs?
  3. Está tudo bem para uma unidade grande ter um bug?
  4. Quantos erros são necessários para causar um desastre?

Suponha que você inicie um novo trabalho e tenha a tarefa de otimizar uma pequena função usada em muitos lugares. Todo o aplicativo foi escrito e mantido por um funcionário que ninguém se lembra. As unidades possuem documentação descrevendo o comportamento esperado normal, mas pouco mais. Qual destes você prefere encontrar?

  • Não há testes de unidade em nenhum lugar do aplicativo. Após fazer a alteração, você pode fazer alguns testes manuais na própria unidade para garantir que ela ainda retorne os valores esperados na documentação. Em seguida, você pode lançá-lo em produção, cruzar os dedos e esperar que funcione (afinal, você sempre escreve código livre de bugs e uma otimização em uma unidade nunca pode afetar outra) ou gasta muito tempo aprendendo como todo o aplicativo funciona para que você possa testar manualmente todas as unidades afetadas direta ou indiretamente.
  • Testes de unidade em todo o aplicativo que são executados automaticamente diariamente ou sob demanda. Eles verificam não apenas os valores normais de entrada e sua resposta esperada, mas também os valores anormais e as exceções esperadas que são geradas. Você faz as alterações e executa o conjunto de testes de unidade para o aplicativo imediatamente, visto que outras três unidades não retornam mais os resultados esperados. Dois deles são benignos, então você ajusta os testes de unidade para explicar isso. O terceiro requer outro pequeno ajuste e um pequeno novo teste de unidade. Depois de fazer as alterações, todo o conjunto de testes é bem-sucedido e você realiza a alteração com confiança.
Leigh Riffel
fonte
1
Em primeiro lugar, obrigado pela sua resposta - não esperava mais nenhum avanço nessa questão ... Em segundo lugar, tenho que admitir que você está certo sobre as operações simples: mesmo um INSERT de duas colunas pode produzir um bug. Se estiver escrito para que a ordem das colunas possa ser comparada com os argumentos, pode ser bom, mas você está certo novamente: provavelmente é melhor manter o aplicativo inteiro sob o regime de teste.
Dez22
@dezso É uma ótima pergunta e um conceito que precisa de muito mais exposição no mundo do banco de dados.
Leigh Riffel
"você deve testar toda a cadeia de eventos como uma unidade" - essa é a coisa mais contra-intuitiva que você poderia dizer. Não é uma unidade, se for esse o caso. Você está fazendo testes de integração
Joe Phillips
@ Joe Philips - Chame como quiser, certificando-se de que um procedimento que faça uma inserção e acione alguns gatilhos faça o que é suposto que seja necessário ter testes automatizados.
Leigh Riffel
8

Para o PostgreSQL, consulte pgTAP :

O pgTAP é um conjunto de funções de banco de dados que facilita a gravação de testes de unidade emissora de TAP em scripts psql ou funções de teste no estilo xUnit.

Frank Heikens
fonte
Vi isso, obrigado. Alguém tem experiência com isso?
Dezso
Sim, muitas pessoas hoje em dia. Inscreva-se na lista de e-mails se tiver dúvidas.
teoria
6

Se você preferir que o teste dos procedimentos armazenados seja feito inteiramente no SQL, consulte http://tsqlt.org/

É compatível com o MS SQL 2005 SP2 e superior, e a vantagem é que os desenvolvedores não precisam conhecer C # ou outro idioma para implementar os testes.

Também há facilidades para criar tabelas e visualizações simuladas para ajudá-lo a obter um conjunto de testes executável novamente.

Alain King
fonte