Отладка сложных систем с БД

Архангельский Андрей

       Конечно есть система отладки, которую предоставляет Delphi. Но что она дает? Создать точку останова, войти в процедуру или обойти ее. А если будет ошибка, то показать регистры процессора. Но программист пишет на языке Паскаль (в Delphi), а результаты отладки ему выдают на языке ассемблера. Кроме того все это позволяет отловить ошибки, когда они вызвали исключение. А в БД ошибки не вызывают исключения — они просто выдают не те данные или просто не выдают никаких. В сложных интерфейсах большую головную боль доставляют последовательности событий — изменяешь одно поле, а в нем вызывается событие onChange и "делает то, что его не просят".
       Вот для этих систем и придумана простая и гибкая система отладки.
       Какие задачи ставились при создании системы:
       1) Выдавать информацию в удобном для разработчика виде, т.е. если это переменная, то выдать "Имя переменной=Значение переменной";
       2) Отслеживать вызовы процедур, а для этого необходимо выдавать информацию не на экран, а в файл протокола.
       3) Для БД необходимо знать какой запрос был сформирован, чтобы протестировать его отдельно в стороннем инструменте, например, EMS Manager. Это означает, что необходимо одной строчкой передать в протокол многострочный запрос.
       4) Система должна работать в MDI-приложении при любом количестве форм.
       Похожая система была в компиляторе с языка Фортран, который разработала фирма DEC. Она позволяла в тексте программы вставлять строки, которые вместо первого символа "C" (комментарий) использовала символ "D" (debug – отладка). При выключенном режиме отладки, эти строки рассматривались как комментарии, а при включенном как обычные операторы.
       Итак, во-первых нужно в проекте определить какую-либо переменную, для того чтобы после отладки убрать эту систему из конечного приложения. В данном случае это AZDEBUG. Для этого необходимо:
       — открыть диалог "Project options";
       — Найти вкладку "Directories/Conditionals"
       — На этой вкладке найти панель "Conditionals" и в поле Conditional defines записать выбранную переменную.
       После отладки, при сборке конечного приложения эту переменную из поля необходимо убрать. Таким образом получился механизм условной трансляции в зависимости от конкретной переменной.
       Дальше необходимо в главной форме добавить переменную, определяющую файл протокола, поставив ее между директивами условной трансляции.

Var
{$IFDEF AZDEBUG}  flError : TextFile;{$ENDIF}

       В событии главной формы FormCreate необходимо написать код, который будет открывать текстовый файл при запуске приложения:

procedure TMainForm.FormCreate(Sender: TObject);
Begin
{$IFDEF AZDEBUG}
   errFileName := ApplPath+StringReplace(ApplName,'.exe','_err.txt',[rfReplaceAll,rfIgnoreCase]);
   AssignFile(flError,errFileName);     ReWrite(flError);
   WriteLn(flError,'<<< Начало работы : '+FormatDateTime('dd"."mm"."yyyy HH:MM:SS',now)+' >>>'); 
{$ENDIF}
End;

       Файл открывается в том же каталоге, где находится приложении и имеет имя – Applname+'_err' с расширением .txt, что позволяет быстро его найти и просмотреть любым текстовым редактором.

procedure TMainForm.FormClose(Sender: TObject; var Action: TCloseAction);
begin
{$IFDEF AZDEBUG} CloseFile(flError); {$ENDIF}
end;

       В событии главной формы FormClose записывается код, который закрывает файл при закрытии формы.
       И, наконец, необходимо определить процедуры для вывода информации. Первая очень простая процедура вывода строки текста WriteReprtText создана только для того, чтобы в подчиненных формах не использовать файловую переменную flError.

{$IFDEF AZDEBUG}
procedure TMainForm.WriteReprtText(txt : String);
begin
  inherited;
  WriteLn(flError,txt);   Flush(flError);
end;

       Вторая процедура WriteReprtStrings выводит в файл массив строк. Причем выводится не только сам массив строк, но и некоторая оформительская информация, как например, переменная Name печатает имя объекта TStrings для удобства отладки. Также выводятся ограничители начала и конца массива строк. Для этой процедуры неважно что выводить - запрос или содержимое ComboBox, главное чтобы это был TStrings.

procedure TMainForm.WriteReprtStrings(Name: String; Str : TStrings);
Var
  cn : Integer;
begin
  inherited;
  WriteLn(flError,'+>>>'+Name+':');
  For cn:=0 to Str.Count-1 do Begin
      writeln(flError,Str.Strings[cn]);
  end;
  WriteLn(flError,'->>>');      Flush(flError);
end;
{$ENDIF}

       Таким образом система отладки готова к использованию. Следующий пример показывает как ее использовать (отладочные операторы выделены наклонным шрифтом):

procedure TfrmConclsKompl.RzCTKomplStateChange(Sender: TObject;  
                          Node: TTreeNode; NewState: TRzCheckState);
Var
  xNParnt,xNCheck : Integer;
  PrntNode : TTreeNode;
begin
{$IFDEF AZDEBUG} MainForm.WriteReprtText('TfrmConclsKompl.RzCTKomplStateChange >>>');{$ENDIF}
  If ExUsrCheck then Begin
  If Node.Level>0 then Begin PrntNode := Node.Parent;  xNParnt := PrntNode.ImageIndex; end
                  else xNParnt := 0;
  xNCheck := Node.ImageIndex;
{$IFDEF AZDEBUG} MainForm.WriteReprtText('Node.text='+Node.Text); {$ENDIF}
  ibqr_ExeProc.Close;    ibqr_ExeProc.SQL.Clear;
  ibqr_ExeProc.SQL.Add('Select * from NSTreeViewCheck');
  ibqr_ExeProc.SQL.Add(' where NSUserID='+IntToStr(AZUserID));
  ibqr_ExeProc.SQL.Add(' and NSConclusn='+IntToStr(CnlsNew.ContrCnls);
  ibqr_ExeProc.SQL.Add(' and NSNodeParnt='+IntToStr(xNParnt));
  ibqr_ExeProc.SQL.Add(' and NSNodeCheck='+IntToStr(xNCheck));
{$IFDEF AZDEBUG} MainForm.WriteReprtStrings('ibqr_ExeProc.SQL',ibqr_ExeProc.SQL); {$ENDIF}
  ibqr_ExeProc.Open;
end;

       Это некоторая процедура обработки события onStateChange.
       Процедура начинается с вывода своего названия в файл протокола. Полезно каждую процедуру в проекте снабдить такой строчкой, для того чтобы знать в каком порядке были вызваны события. В критических случаях можно в эту (или следующую строчку) добавить значения параметров, с которыми процедура вызывалась.
       Следующая строчка (для отладки) выводит значение узла дерева, с которым производится операция.
       После чего формируется не очень сложный запрос, но любой из параметров может привести к тому, что запрос не будет возвращать значения. Поэтому ДО ТОГО как будет выполнен оператор ibqr_ExeProc.Open в файл протокола выводится сформированный запрос. Выводит его после оператора Open нельзя, так как если в запросе есть ошибка с исключением, то выполнение всей оставшейся части процедуры будет прекращено.
       Таким образом, после размещения строк с отладочной информацией, пользователь запустив приложение и проделав некоторые действия получит протокол, в котором фиксируются его действия и события, которые они вызвали, а также значения тех переменных, для которых установлен контроль.

© 25.04.2006, Архангельский А.Г.




Поддержите культуру
ЯндексЯндекс. ДеньгиХочу такую же кнопку

Google
 
Web azdesign.ru az-libr.ru


Дата последнего изменения:
Wednesday, 23-Oct-2013 09:02:56 UTC