IdTest.pas 4.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210
  1. unit IdTest;
  2. {
  3. minimal/example test runner for .net/mono
  4. feel free to improve this code
  5. for example, better format for the output
  6. }
  7. interface
  8. uses
  9. System.Reflection,
  10. System.Threading,
  11. IdObjs,
  12. IdBaseComponent;
  13. type
  14. TIdTest = class;
  15. TIdTestClass = class of TIdTest;
  16. TOutputStringProcedure = procedure(const AString: string);
  17. TIdTest = class(TIdBaseComponent)
  18. private
  19. FOnOutputString: TOutputStringProcedure;
  20. protected
  21. procedure SetUp; virtual;
  22. procedure TearDown; virtual;
  23. public
  24. procedure OutputLn(const ALine: string);
  25. class procedure RegisterTest(const aClass:TIdTestClass);
  26. class function TestList:TIdList;
  27. property OnOutputString: TOutputStringProcedure read FOnOutputString write FOnOutputString;
  28. end;
  29. TIdBasicRunner = class(TObject)
  30. private
  31. FLockObj: &Object;
  32. FDebugInfo: Boolean;
  33. procedure WriteLn(const aStr:string);
  34. procedure WriteOutput(const AString: string);
  35. procedure RecordPass(const aTest:TIdTest;const aMethod:string);
  36. procedure RecordFail(const aTest:TIdTest;const aMethod:string;const e:exception);
  37. procedure WriteString(const AString: string);
  38. public
  39. PassCount:integer;
  40. FailCount:integer;
  41. constructor Create;
  42. procedure Execute;
  43. end;
  44. implementation
  45. var
  46. // this should really be a classlist
  47. FRegisterList:TIdList;
  48. class procedure TIdTest.RegisterTest(const aClass: TIdTestClass);
  49. begin
  50. TestList.Add(aClass.Create);
  51. end;
  52. class function TIdTest.TestList: TIdList;
  53. begin
  54. if FRegisterList=nil then
  55. begin
  56. FRegisterList:=TIdList.Create;
  57. end;
  58. Result:=FRegisterList;
  59. end;
  60. procedure TIdTest.OutputLn(const ALine: string);
  61. begin
  62. if Assigned(FOnOutputString) then
  63. begin
  64. FOnOutputString(ALine + Environment.NewLine);
  65. end;
  66. end;
  67. { TIdBasicRunner }
  68. constructor TIdBasicRunner.Create;
  69. function ShouldOutputDebuggingInfo: Boolean;
  70. var
  71. I: Integer;
  72. begin
  73. Result := False;
  74. for I := 0 to High(Environment.GetCommandLineArgs) do
  75. Result := Result or (Environment.GetCommandLineArgs[i].ToLower = '/debug');
  76. end;
  77. begin
  78. inherited;
  79. FLockObj := &Object.Create;
  80. FDebugInfo := ShouldOutputDebuggingInfo;
  81. end;
  82. procedure TIdBasicRunner.WriteOutput(const AString: string);
  83. begin
  84. WriteString('INFO: ' + AString);
  85. end;
  86. procedure TIdBasicRunner.WriteString(const AString: string);
  87. begin
  88. if FDebugInfo then
  89. begin
  90. Monitor.Enter(FLockObj);
  91. try
  92. Console.Write(' ' + AString);
  93. finally
  94. Monitor.Exit(FLockObj);
  95. end;
  96. end;
  97. end;
  98. procedure TIdBasicRunner.Execute;
  99. var
  100. aMethods:array of methodinfo;
  101. aMethodCount:integer;
  102. aTestCount:integer;
  103. aMethod:methodinfo;
  104. aTest:TIdTest;
  105. begin
  106. PassCount:=0;
  107. FailCount:=0;
  108. for aTestCount:=0 to TIdTest.TestList.Count-1 do
  109. begin
  110. aTest:=TIdTest.TestList[aTestCount] as TIdTest; //aClass.Create();
  111. aTest.OnOutputString := WriteOutput;
  112. aMethods:=aTest.GetType.GetMethods;
  113. WriteLn('Test:'+aTest.classname);
  114. for aMethodCount:=low(aMethods) to high(aMethods) do
  115. begin
  116. aMethod:=aMethods[aMethodCount];
  117. if not aMethod.Name.StartsWith('Test') then continue;
  118. try
  119. WriteLn(' ' + aMethod.Name);
  120. aTest.SetUp;
  121. try
  122. aMethod.Invoke(aTest,[]);
  123. finally
  124. aTest.TearDown;
  125. end;
  126. //commented out, makes easier to see the fails
  127. RecordPass(aTest,aMethod.name);
  128. except
  129. on e:exception do
  130. begin
  131. RecordFail(aTest,aMethod.name,e);
  132. end;
  133. end;
  134. end; //methods
  135. end; //tests
  136. WriteLn('Results: Pass='+PassCount.ToString+', Fail='+FailCount.ToString);
  137. end;
  138. procedure TIdBasicRunner.RecordPass(const aTest: TIdTest;
  139. const aMethod: string);
  140. begin
  141. inc(PassCount);
  142. WriteString('Passed' + Environment.NewLine);
  143. end;
  144. procedure TIdBasicRunner.RecordFail(const aTest: TIdTest; const aMethod: string;
  145. const e: exception);
  146. var
  147. ie:TargetInvocationException;
  148. begin
  149. inc(failcount);
  150. WriteLn(' Fail:');
  151. //this exception is raised as we are calling methods using reflection
  152. if e is TargetInvocationException then
  153. begin
  154. ie:=e as TargetInvocationException;
  155. WriteLn(' '+ie.InnerException.classname+':'+ie.InnerException.Message);
  156. WriteLn(ie.InnerException.StackTrace);
  157. end else begin
  158. WriteLn(' '+e.classname);
  159. end;
  160. end;
  161. procedure TIdBasicRunner.WriteLn(const aStr: string);
  162. begin
  163. Monitor.Enter(FLockObj);
  164. try
  165. Console.WriteLine(AStr);
  166. finally
  167. Monitor.Exit(FLockObj);
  168. end;
  169. end;
  170. procedure TIdTest.SetUp;
  171. begin
  172. end;
  173. procedure TIdTest.TearDown;
  174. begin
  175. end;
  176. end.