Utilizando Assertions em Delphi
Assertions são validações sobre os fundamentos da lógica de um programa. A verificação de um assertion é a validação de que uma condição necessária para o algoritimo funcionar, algo que você supõe ser verdadeiro, é realmente válido durante a execução do programa.
Em Delphi, a sintaxe de um Assertion é a seguinte:
Assert(Condition: Boolean; [Message: string]);
Isso quer dizer que Assert é um procedimento que aceita uma condição, e opcionalmente uma mensagem de erro. É usado como uma prática defensiva de codificação para garantir o estado do seu programa, pegando falhas antes que aconteçam. Se a condição passada para o assert for avaliada como falso, será gerada uma exceção com a mensagem informada (ou ‘assertion failure’, se não for passada nenhuma), e o mais interessante, por uma mágica de compilador a mensagem também inclui o nome do arquivo e a linha onde a falha ocorreu.
Assertions não são feitas para validação de entrada de dados ou de resultados de funções, mas sim de pressupostos que deveriam sempre ser verdadeiros, e se não forem, indicam existe uma bug em alguma parte do seu programa. Por esse motivo, é prática comum desabilitar a validação de assertions no executável final produzido para distribuição, o que pode ser feito através de Project/Options, Compiler, Debug Information, Assertions.
Tendo em mente tudo isso, vamos a alguns exemplos:
procedure TMinhaClasse.AdicionaItem(Item: TMeuItem); begin Assert(Assigned(Item), 'Foi passado um item nil!'); // ERRADO! FList.Add(Item); end;
Um Assertion Failure não é uma validação apropriada para a validação de parâmetros de métodos públicos. Enquanto seria aceitável se esse método fosse chamado apenas internamente, se ele for disponibilizado para outros desenvolvedores ou para ser utilizado em outras classes, ele deve funcionar corretamente em todos os casos, com assertions habilitadas ou não. Desta forma, poderiamos escrever
procedure TMinhaClasse.AdicionaItem(Item: TMeuItem);
begin
if not Assigned(Item) then
raise Exception.Create('Foi passado um item nil!');
Assert(FList.Add(Item) >= 0, 'Item não foi adicionado corretamente'); //ERRADO!
end;
Esta segunda tentativa de utilizar o assert também é falha, pois coloca código importante dentro do assert. Se essa classe for compilada com assertions desligados, esse código não vai ser executado e a lógica não vai mais funcionar.
procedure TMinhaClasse.AdicionaItem(Item: TMeuItem);
begin
if not Assigned(Item) then
raise Exception.Create('Foi passado um item nil!');
Assert(Assigned(FLista), "FLista é nil');
FList.Add(Item);
end;
Neste último exemplo estamos fazendo uma validação adequada para um assert – FLista deve estar sempre atribuída durante o tempo de vida da classe. Se não tiver, é um problema da lógica interna da classe (e não um problema externo como a validação do parâmetro). Essa validação apontaria o erro adequadamente durante a depuração, evitando causar um Access Violation mais dificil se se diagnosticar. E, caso seja removida para o executável de produção, não vai causar nenhum comportamento diferente no programa.
Em 09 de junho de 2007 às 16:54
Dica (de quem já passou vergonha por deixar uma mensagem do Assert ser exibida em um cliente):
Se desabilitar assertions no executável final, não se esqueça de incluir os arquivos .CFG no controle fontes, ou caso contrário quando você precisar mudar a máquina que gera a versão de produção você pode se esquecer e liberar uma versão com mensagens inapropriadas.
Outras formas de evitar constrangimentos com asserts na versão final:
1) Testar se DebugHook 0 antes de cada assert, já que muitas vezes só nos interessam mesmo durante a fase de debug;
2) Desligar, por diretiva de compilação ({$ASSERTIONS OFF}), em cada arquivo (tem como desabilitar uma diretiva para todo o projeto?) que utiliza asserts, e só ligá-los quando precisar debugar;
3) E a mais importante: não utilize mensagens constrangedoras como: “FLista tá nil de novo. Seu burro!!!”.
Em 23 de agosto de 2008 às 03:51
Muito interessante e útil esse Assert
Em 15 de abril de 2009 às 11:51
Vejo que assertions pode ser muito útil, em aplicações muito complexas, erros de lógica as vezes acontecem e acabam chegando ao cliente final inevitávelmente. Para agilizar a manutenção desses “Bugs”, gostaria de usar essa técnica somente para me retornar a linha de código onde está acontecendo um erro, como por exemplo, citado acima.
Alguém tem alguma opnião sobre o uso de Asserts com essa finalidade? É recomendável esse tipo de uso?
Em 10 de maio de 2010 às 22:59
[...] Alias, andei pesquisamento melhor, e descobri que o Delphi suporta Assertions, um recurso muito útil para evitas este tipo de problema. Existem um ótimo tutorial no TechTips sobre isso, vale a pena dar uma conferida. http://www.techtips.com.br/programacao/delphi/linguagem-delphi/utilizando-assertions-em-delphi/ [...]