Original in Russian: http://18delphi.blogspot.ru/2013/11/2.html
GUI-testing. Table of contents
Now that I have been developing a bit I began to think about parsing for tokens.
The code has become like this:
In some way this is - TDD (https://en.wikipedia.org/wiki/Test-driven_development).
When you write the code and think of testing it THEN AND THERE.
And about “where to see the results of the code”.
It is better to do it on FILE system, NOT in the debugger.
If you load such “etalons” in CVS/SVN, you can see REGRESSION AT ONCE (https://en.wikipedia.org/wiki/Regression_testing).
How it can be added to DUnit and how to “automatically compare etalons” – I will tell a bit later.
GUI-testing. Table of contents
Now that I have been developing a bit I began to think about parsing for tokens.
The code has become like this:
unit Script.Parser; interface uses Classes, CoreObject ; {$IfNDef NoTesting} {$Define TestParser} {$EndIf NoTesting} type TscriptParser = class(TCoreObject) private f_Stream : TStream; {$IfDef TestParser} f_GetCharLog : TStream; // - right away we think of testing, we’ll output in this stream // the result of function GetChar f_ReadLnLog : TStream; // - right away we think of testing, we’ll output in this stream // the result of function ReadLn f_TokenLog : TStream; // - right away we think of testing, we’ll output in this stream // the result of function NextToken {$EndIf TestParser} f_EOF : Boolean; f_CurrentLine : String; f_PosInCurrentLine : Integer; f_Token : String; {$IfDef TestParser} private procedure WriteLineToLog(const aLine: AnsiString; aLog: TStream); {$EndIf TestParser} protected procedure Cleanup; override; function ReadLn: String; protected function GetChar(out aChar: AnsiChar): Boolean; public constructor Create(const aStream : TStream; const aFileName : String); overload; constructor Create(const aFileName : String); overload; function EOF: Boolean; procedure NextToken; end;//TscriptParser implementation uses System.SysUtils ; constructor TscriptParser.Create(const aStream : TStream; const aFileName : String); begin inherited Create; f_PosInCurrentLine := 1; f_EOF := false; f_Stream := aStream; {$IfDef TestParser} f_GetCharLog := TFileStream.Create(aFileName + '.GetChar.log', fmCreate); f_ReadLnLog := TFileStream.Create(aFileName + '.ReadLn.log', fmCreate); f_TokenLog := TFileStream.Create(aFileName + '.Token.log', fmCreate); {$EndIf TestParser} end; constructor TscriptParser.Create(const aFileName : String); var l_FileName : String; begin l_FileName := ExtractFilePath(ParamStr(0)) + '\' + aFileName; Create(TFileStream.Create(l_FileName, fmOpenRead), l_FileName); end; procedure TscriptParser.Cleanup; begin FreeAndNil(f_Stream); {$IfDef TestParser} FreeAndNil(f_TokenLog); FreeAndNil(f_GetCharLog); FreeAndNil(f_ReadLnLog); {$EndIf TestParser} inherited; end; function TscriptParser.GetChar(out aChar: AnsiChar): Boolean; begin if (f_Stream.Read(aChar, SizeOf(aChar)) = SizeOf(aChar)) then begin Result := true; {$IfDef TestParser} f_GetCharLog.Write(aChar, SizeOf(aChar)); {$EndIf TestParser} end else Result := false; end; {$IfDef TestParser} procedure TscriptParser.WriteLineToLog(const aLine: AnsiString; aLog: TStream); const cEOL : AnsiString = #13#10; begin aLog.Write(@aLine[1], Length(aLine)); aLog.Write(@cEOL[1], Length(cEOL)); end; {$EndIf TestParser} function TscriptParser.ReadLn: String; {$IfDef TestParser} var l_Result : AnsiString; {$EndIf TestParser} var l_Char : AnsiChar; l_Line : String; l_LineCommentPos : Integer; begin {$IfDef TestParser} try {$EndIf TestParser} try l_Line := ''; while GetChar(l_Char) do begin if (l_Char = #13) then begin if GetChar(l_Char) then begin if (l_Char = #10) then begin Result := l_Line; Exit; end//l_Char = #10 else Assert(false, 'Something has gone wrong, there is no character 10 after 13'); end//GetChar(l_Char) else Assert(false, 'Something has gone wrong, at once the file end after character 13'); end;//l_Char = #13 l_Line := l_Line + l_Char; end;//while GetChar(l_Char) f_EOF := true; Result := l_Line; finally l_LineCommentPos := Pos('//', Result); if (l_LineCommentPos > 0) then begin Delete(Result, l_LineCommentPos, Length(Result) - l_LineCommentPos + 1); end;//l_LineCommentPos > 0 end;//try..finally {$IfDef TestParser} finally WriteLineToLog(Result, f_ReadLnLog); end;//try..finally {$EndIf TestParser} end; procedure TscriptParser.NextToken; begin if (f_PosInCurrentLine > Length(f_CurrentLine)) then begin // - The WHOLE current line kind of has been processed f_CurrentLine := ''; f_PosInCurrentLine := 1; end;//f_PosInCurrentLine > Length(f_CurrentLine) while(f_CurrentLine = '') do begin f_CurrentLine := ReadLn; if (f_CurrentLine = '') then if f_EOF then Exit; end;//while(f_NextToken = '') f_Token := ''; {$IfDef TestParser} WriteLineToLog(f_Token, f_TokenLog); {$EndIf TestParser} f_CurrentLine := ''; end; function TscriptParser.EOF: Boolean; begin Result := f_EOF; end; end.
In some way this is - TDD (https://en.wikipedia.org/wiki/Test-driven_development).
When you write the code and think of testing it THEN AND THERE.
And about “where to see the results of the code”.
It is better to do it on FILE system, NOT in the debugger.
If you load such “etalons” in CVS/SVN, you can see REGRESSION AT ONCE (https://en.wikipedia.org/wiki/Regression_testing).
How it can be added to DUnit and how to “automatically compare etalons” – I will tell a bit later.
Комментариев нет:
Отправить комментарий