Aceitando a conveniência de usar testes de unidade no meu C ++ favorito, tentei transferir minha experiência para o TSQL, especialmente porque o novo empregador adora uma iniciativa útil localmente e distribui pães para ela.
Examinei várias
estruturas conhecidas, cheguei à conclusão de que, em regra, elas são volumosas e trazem sintaxe adicional que precisa ser estudada adicionalmente.
Algumas estruturas funcionam lindamente e agradam aos olhos do gerente, para quem elas são exibidas, mas têm várias limitações que eu não gostei.
Eu queria implementar tudo em TSQL puro ortodoxo kosher-halal.
De tempos em tempos, distraindo o desenvolvimento principal por vários anos, aprimorando a estrutura do script, decidi compartilhá-lo com você (mas ainda consegui produzir 3,5 Mb de scripts).
Os requisitos básicos para mim eram simples - eu tenho que executar qualquer teste de unidade em um arquivo sem a necessidade de gestos e ferramentas de software especiais - apenas incondicionais: sqlcmd ou MSSMS.
Nenhuma alteração é feita no banco de dados no qual o teste é executado - tudo é revertido para o início do script.
Apenas um estabeleceu uma limitação - o teste deve funcionar em um banco de dados vazio (dados iniciais podem ser); caso contrário, você se cansa de desmontar todas as opções.
A principal tarefa é testar a lógica e manter a integridade da lógica.
Para isso, coloquei o seguinte cabeçalho no início do teste:
SET QUOTED_IDENTIFIER ON GO PRINT '-------------------------------- CLR Unit tests for Habr Logic ---------------------------------' IF 0 < ( SELECT count(*) FROM device) begin RAISERROR ('FAILED: database must be empty for this unit test', 16, -1 ) end GO
Tento não criar testes de unidade com mais de duas telas, embora isso não seja fácil, no caso de lógica complexa.
Um teste de unidade típico se parece com isso e tem três partes principais:
BEGIN TRAN TestClr2 declare @test_name sysname = (select TOP 1 name from sys.dm_tran_active_transactions WHERE transaction_type = 1 ORDER BY transaction_begin_time DESC) + ' [fn_calculate_dev_status] record for device has wrong range' BEGIN TRY SET NOCOUNT ON;
- 1. preparar dados para teste de unidadeAqui, podemos preencher as tabelas necessárias com dados e preparar algumas variáveis ou tabelas temporárias para não confundir o código na seção de teste.
- 2. executar teste de unidadeAqui, como regra geral, uma chamada de função, um procedimento ou uma alteração de tabela, se testarmos a lógica do acionador.
- 3. verificação de resultadosNesta parte do teste, verificamos como o estado dos objetos do banco de dados mudou ou o resultado do procedimento de função testado.
Se a função de procedimento retorna um registro, então o inserimos na tabela temporária e o analisamos já.
Os resultados agregados e preparados são comparados com o padrão e lançam uma exceção se tudo mais falhar.
Com a Oracle, tudo é um pouco mais complicado - não pude escrever e executar o teste dessa forma e na mesma ideologia, em vez de uma pequena experiência - paramos de oferecer suporte ao Oracle para o nosso produto.
Cada teste de unidade é emitido como um procedimento:
CREATE OR REPLACE PROCEDURE UnitTest9_TRG_JOBLOGDETAIL AS v_message VARCHAR2(255) := 'UnitTest9_TRG_JOBLOGDETAIL: INSERT joblogdetail]- joblogdetail_result not Failed and joblogdetail_endtime is null '; v_maxdate date := '2014/01/01'; v_cnt NUMBER := 0; BEGIN savepoint my_savepoint; <b>
No mesmo arquivo de teste no final, você terá que fazer uma limpeza do banco de dados a partir dos testes criados e executados.
commit; / set serveroutput on; SET FEEDBACK OFF; spool C:\dist\test.spl; exec UnitTest_empty_database; exec UnitTest3297_TRGBFR_UDEVICE(1); exec UnitTest5_TRG_BF_UDEVICE; exec UnitTest_3062a; ... spool off; / DROP PROCEDURE UnitTest_3062; DROP PROCEDURE UnitTest_BIRDIESEC_3344; DROP PROCEDURE UnitTest_empty_database; ... SET FEEDBACK ON; commit;
Só isso.
Em seguida, você apenas produz arquivos, divididos em categorias do tipo: gatilhos, funções, procedimentos, relatórios, objetos grandes e especiais da lógica de negócios e, é claro, para cada objeto de banco de dados.
Quase todos os desenvolvedores de banco de dados franzem a testa e dizem - por que devo deixar os testadores fazer isso. Se o banco de dados não possui lógica da palavra, concordo com eles, mas se houver muito, eles naturalmente salvam os nervos, a reputação e o dinheiro.
Um exemplo
Temos na interface da web árvores de conexões lógicas entre objetos de árvore como América -> Canadá -> Ontário -> Waterloo, Ásia -> Japão -> Tóquio -> Ebina, ou seja, toda uma série de escritórios geográficos.
Cada nó desse tipo possui regras muito complexas, o usuário ou regra ou gerador atribui dispositivos.
Como resultado, mesmo as instruções descritas em detalhes em etapas demolem todos, mesmo aqueles que participaram da discussão e desenvolvimento dessa lógica.
Mais de cinquenta etapas da instrução com diferentes conjuntos de dados - tudo é documentado em detalhes.
Qualquer alteração ou adição à lógica é um relógio de verificação manual de que nada quebrou.
A refatoração da morte é semelhante.
Depois de cobrir a lógica com testes de unidade, tudo é verificado pela seda e tenho certeza de que tudo está funcionando como deveria.
Qualquer desenvolvedor de Java que recorra a mim, lançando trovões e raios (pensando consigo mesmo em minhas mãos tortas) é facilmente colocado em prática executando o teste apropriado.
Alguns minutos e todos estão satisfeitos. Qualquer alteração fatal do código na minha ausência será rapidamente relatada por correio.
Naturalmente, como uma pessoa preguiçosa, decidi automatizar tudo para a Automação Contínua e escrevi mingau a partir de lotes e python.
Peço que você execute um pouco. No desenvolvimento diário de quase uma dúzia de linguagens e ambientes entre os quais você precisa pular, há uma catastrófica falta de tempo para lamber tudo e colocá-lo em uma aparência profissional.
Eu não queria fazer tudo no windows powershell - nossos saltos ainda são executados aqui e ali no windows95 incorporado.
Eu queria fazer todas as chamadas em Python, mas descobriu-se que algumas construções sql (análise de XML dentro de cte) não são suportadas não apenas na biblioteca python, mas também no .NET, então fiz o script através do sqlcmd.
O código está publicado
aqui .
Para executar um exemplo prático, basta editar 2 arquivos: smtppart.py e config.ini - nome do servidor SMTP, porta e email onde as mensagens de erro serão descartadas.
Os scripts primeiro tentam obter as atualizações mais recentes do svn (substitua pelo seu - git, perforce, ...).
Em seguida, uma base limpa é criada a partir de scripts com um nome aleatório, os testes de unidade são iniciados nela e a base é excluída.
A criação de um banco de dados de scripts de 80 Mb e testes de 3,5 Mb (a parte principal do esquema já foi feita antes de eu ingressar na empresa, portanto testei apenas minha parte) é feita na minha máquina em cerca de 15 minutos. Eu só tenho tempo para beber uma xícara de café antes da confirmação final.
Se houver erros, os resultados do erro serão enviados por email.
A instalação de dependência é descrita no arquivo: readme.txt
Após cada alteração de código, você deve definir manualmente o hash do código (ele será visto na linha de comando) no arquivo config.ini - a mensagem será exibida mesmo que o código seja alterado e nada seja quebrado - para que eu possa controlar as alterações no código para poder verificar as alterações sem meu envolvimento prévio.

O início de todos os testes de unidade no arquivo autorun.bat pode ser colocado no
Agendador de Tarefas do
Windows para execução de 1 a 2 dias antes da criação da empresa ou depois de sair de casa - se algo acontecer à noite - você pode ver o que aconteceu na frente da TV e corrigi-lo rapidamente.
Sei que nos testes de unidade é o mais difícil de configurar tudo e, em seguida, é fácil e agradável escrever testes, embora possa ser difícil e difícil, mas necessário. Boa sorte nos testes, espero que meu conselho ajude alguém.
Ficarei feliz em receber conselhos se algo puder ser melhorado em algum lugar e pentear o código, não julgue rigorosamente.