TestExtensions.pas
上传用户:yjb1804
上传日期:2021-01-30
资源大小:3105k
文件大小:12k
源码类别:

Email服务器

开发平台:

Delphi

  1. { $Id: TestExtensions.pas,v 1.42 2006/07/19 02:45:55 judc Exp $ }
  2. {: DUnit: An XTreme testing framework for Delphi programs.
  3.    @author  The DUnit Group.
  4.    @version $Revision: 1.42 $
  5. }
  6. (*
  7.  * The contents of this file are subject to the Mozilla Public
  8.  * License Version 1.1 (the "License"); you may not use this file
  9.  * except in compliance with the License. You may obtain a copy of
  10.  * the License at http://www.mozilla.org/MPL/
  11.  *
  12.  * Software distributed under the License is distributed on an "AS
  13.  * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
  14.  * implied. See the License for the specific language governing
  15.  * rights and limitations under the License.
  16.  *
  17.  * The Original Code is DUnit.
  18.  *
  19.  * The Initial Developers of the Original Code are Kent Beck, Erich Gamma,
  20.  * and Juancarlo A馿z.
  21.  * Portions created The Initial Developers are Copyright (C) 1999-2000.
  22.  * Portions created by The DUnit Group are Copyright (C) 2000-2004.
  23.  * All rights reserved.
  24.  *
  25.  * Contributor(s):
  26.  * Kent Beck <kentbeck@csi.com>
  27.  * Erich Gamma <Erich_Gamma@oti.com>
  28.  * Juanco A馿z <juanco@users.sourceforge.net>
  29.  * Chris Morris <chrismo@users.sourceforge.net>
  30.  * Jeff Moore <JeffMoore@users.sourceforge.net>
  31.  * Kenneth Semeijn <kennethsem@users.sourceforge.net>
  32.  * Kris Golko <neuromancer@users.sourceforge.net>
  33.  * The DUnit group at SourceForge <http://dunit.sourceforge.net>
  34.  *
  35.  *)
  36. // memory calculations may produce integer overflows
  37. {$OVERFLOWCHECKS OFF}
  38. unit TestExtensions;
  39. interface
  40. uses
  41.   Classes,
  42.   IniFiles,
  43.   TestFramework;
  44. type
  45.   TMemorySize = Longint;
  46.   {:A Decorator for Tests. Use TTestDecorator as the base class
  47.     for defining new test decorators. Test decorator subclasses
  48.     can be introduced to add behaviour before or after a test
  49.     is run. }
  50.   TTestDecorator = class(TAbstractTest, ITestDecorator, ITest)
  51.   protected
  52.     FName:  string;
  53.     FTest:  ITest;
  54.     FTests: IInterfaceList;
  55.     function GetTest: ITest;
  56.     {: Overrides the inherited behavior and executes the
  57.        decorated test's RunTest instead }
  58.     procedure RunTest(ATestResult: TTestResult); override;
  59.   public
  60.     {: Decorate a test. If no name parameter is given, the decorator
  61.        will be named as the decorated test, with some extra information
  62.        prepended.
  63.        @param ATest The test to decorate.
  64.        @param AName  Optional name to give to the decorator. }
  65.     constructor Create(ATest: ITest; AName: string = '');
  66.     function  CountTestCases: integer;          override;
  67.     function  CountEnabledTestCases: integer;   override;
  68.     { ITestDecorator implementation }
  69.     function  GetName: string;                  override;
  70.     function  Tests: IInterfaceList;            override;
  71.     procedure LoadConfiguration(const iniFile :TCustomIniFile; const section :string);  override;
  72.     procedure SaveConfiguration(const iniFile :TCustomIniFile; const section :string);  override;
  73.     property Test: ITest read GetTest;
  74.   end;
  75.   {:A Decorator to set up and tear down additional fixture state.
  76.     Subclass TestSetup and insert it into your tests when you want
  77.     to set up additional state once before the tests are run.
  78.     @example <br>
  79.     <code>
  80.     function UnitTests: ITest;
  81.     begin
  82.       Result := TSetubDBDecorator.Create(TDatabaseTests.Suite, 10);
  83.     end; </code> }
  84.   TTestSetup = class(TTestDecorator)
  85.   protected
  86.   public
  87.     constructor Create(ATest: ITest; AName: string = '');
  88.     function  GetName: string;                  override;
  89.     // default decorator behavior is enough to provide for Setup decoration
  90.     // procedure RunTest(ATestResult: TTestResult); override;
  91.   end;
  92.  {:A test decorator that runs a test repeatedly.
  93.    Use TRepeatedTest to run a given test or suite a specific number
  94.    of times.
  95.     @example <br>
  96.     <code>
  97.     function UnitTests: ITestSuite;
  98.     begin
  99.       Result := TRepeatedTest.Create(ATestArithmetic.Suite, 10);
  100.     end;
  101.     </code> }
  102.   {: General interface for test decorators}
  103.   IRepeatedTest = interface(IUnknown)
  104.   ['{DF3B52FF-2645-42C2-958A-174FF87A19B8}']
  105.     function  GetHaltOnError: Boolean;
  106.     procedure SetHaltOnError(const Value: Boolean);
  107.     property  HaltOnError: Boolean read GetHaltOnError write SetHaltOnError;
  108.   end;
  109.   TRepeatedTest = class(TTestDecorator, IRepeatedTest)
  110.   private
  111.     FTimesRepeat: integer;
  112.     FHaltOnError: Boolean;
  113.     function  GetHaltOnError: Boolean;
  114.     procedure SetHaltOnError(const Value: Boolean);
  115.   protected
  116.     {: Overrides the behavior of the base class as to execute
  117.        the test repeatedly. }
  118.     procedure RunTest(ATestResult: TTestResult);  override;
  119.   public
  120.     {: Construct decorator that repeats the decorated test.
  121.        The ITest parameter can hold a single test or a suite. The Name parameter
  122.        is optional.
  123.        @param ATest The test to repeat.
  124.        @param Itrations The number of times to repeat the test.
  125.        @param AName An optional name to give to the decorator instance }
  126.     constructor Create(ATest: ITest; Iterations: integer; AName: string = '');
  127.     function  GetName: string;                    override;
  128.     {: Overrides the inherited behavior to included the number of repetitions.
  129.        @return Iterations * inherited CountTestCases }
  130.     function  CountTestCases: integer;            override;
  131.     {: Overrides the inherited behavior to included the number of repetitions.
  132.        @return Iterations * inherited CountEnabledTestCases }
  133.     function  CountEnabledTestCases: integer;     override;
  134.   published
  135.     property  HaltOnError: Boolean read GetHaltOnError write SetHaltOnError;
  136.   end;
  137.   {: A test decorator for running tests in a separate thread
  138.      @todo Implement this class }
  139.   TActiveTest = class(TTestDecorator)
  140.   end;
  141.   {: A test decorator for running tests expecting a specific exceptions
  142.      to be thrown.
  143.      @todo Implement this class }
  144.   TExceptionTestCase = class(TTestDecorator)
  145.   end;
  146.   {: A test decorator for running tests while checking memory when a test is
  147.    successful, expecting the memory to be equal before and after the SetUp,
  148.    Run and TearDown.
  149.    This decorator does not function correctly when the tested code
  150.    creates singleton objects or strings that are not set to ''.
  151.    Testing after the normal test run tests the memory with singletons in place.
  152.     @example <br>
  153.     <code>
  154.     function UnitTests: ITestSuite;
  155.     begin
  156.       Result := TMemoryTest.Create(ATestArithmetic.Suite);
  157.     end;
  158.     </code> }
  159. {$IFNDEF CLR}
  160.   EMemoryError = class(ETestFailure);
  161.   TMemoryTestTypes = (mttMemoryTestBeforeNormalTest, mttExecuteNormalTest, mttMemoryTestAfterNormalTest);
  162.   TMemoryTestTypesSet = set of TMemoryTestTypes;
  163.   TMemoryTest = class(TTestDecorator)
  164.   protected
  165.     function MemoryAllocated: TMemorySize;
  166.   public
  167.     function GetName : string; override;
  168.     procedure RunTest(ATestResult: TTestResult); override;
  169.   end;
  170. {$ENDIF}
  171. implementation
  172. uses
  173.   {$IFDEF LINUX} Libc, {$ENDIF}
  174.   {$IFDEF FASTMM}
  175.      FastMM4,
  176.   {$ENDIF}
  177.   SysUtils;
  178. { TTestDecorator }
  179. procedure TTestDecorator.RunTest(ATestResult: TTestResult);
  180. begin
  181.   FTest.RunWithFixture(ATestResult);
  182. end;
  183. function TTestDecorator.CountEnabledTestCases: integer;
  184. begin
  185.   if Enabled then
  186.     Result := FTest.countEnabledTestCases
  187.   else
  188.     Result := 0;
  189. end;
  190. function TTestDecorator.CountTestCases: integer;
  191. begin
  192.   if Enabled then
  193.     Result := FTest.countTestCases
  194.   else
  195.     Result := 0;
  196. end;
  197. constructor TTestDecorator.Create(ATest: ITest; AName: string);
  198. begin
  199.   if AName <> '' then
  200.     inherited Create(AName)
  201.   else
  202.     inherited Create(ATest.Name);
  203.   FTest := ATest;
  204.   FTests:= TInterfaceList.Create;
  205.   FTests.Add(FTest);
  206. end;
  207. function TTestDecorator.GetTest: ITest;
  208. begin
  209.   Result := FTest;
  210. end;
  211. procedure TTestDecorator.LoadConfiguration(const iniFile: TCustomIniFile; const section: string);
  212. var
  213.   i    : integer;
  214.   LTests: IInterfaceList;
  215. begin
  216.   inherited LoadConfiguration(iniFile, section);
  217.   LTests := self.Tests;
  218.   for i := 0 to LTests.count-1 do
  219.     (LTests[i] as ITest).LoadConfiguration(iniFile, section + '.' + self.GetName);
  220. end;
  221. procedure TTestDecorator.SaveConfiguration(const iniFile: TCustomIniFile; const section: string);
  222. var
  223.   i    : integer;
  224.   LTests: IInterfaceList;
  225. begin
  226.   inherited SaveConfiguration(iniFile, section);
  227.   LTests := self.Tests;
  228.   for i := 0 to LTests.count-1 do
  229.     (LTests[i] as ITest).SaveConfiguration(iniFile, section + '.' + self.GetName);
  230. end;
  231. function TTestDecorator.tests: IInterfaceList;
  232. begin
  233.   Result := FTests;
  234. end;
  235. function TTestDecorator.GetName: string;
  236. begin
  237.   Result := Format('(d) %s', [getTest.Name]);
  238. end;
  239. type
  240.   {
  241.     TTestSetupStub
  242.     This class decorates the Setup decorator
  243.     when called with then
  244.     TTestSetup.CreateDecoratedTest function.
  245.   }
  246.   TTestSetupStub = class(TTestSetup)
  247.   private
  248.     FStubTest : ITest;
  249.   protected
  250.     procedure SetUp; override;
  251.     procedure TearDown; override;
  252.   end;
  253. { TTestSetupStub }
  254. procedure TTestSetupStub.SetUp;
  255. begin
  256.   // Delegate the set up to the real implementation
  257.   FStubTest.SetUp;
  258. end;
  259. procedure TTestSetupStub.TearDown;
  260. begin
  261.   // Delegate the teardown to the real implementation
  262.   FStubTest.TearDown;
  263. end;
  264. { TTestSetup }
  265. constructor TTestSetup.Create(ATest: ITest; AName: string);
  266. begin
  267.   inherited Create(ATest, AName);
  268. end;
  269. function TTestSetup.GetName: string;
  270. begin
  271.   Result := Format('Setup decorator (%s)', [inherited GetName]);
  272. end;
  273. { TRepeatedTest }
  274. function TRepeatedTest.CountEnabledTestCases: integer;
  275. begin
  276.   Result := inherited CountEnabledTestCases * FTimesRepeat;
  277. end;
  278. function TRepeatedTest.CountTestCases: integer;
  279. begin
  280.   Result := inherited CountTestCases * FTimesRepeat;
  281. end;
  282. constructor TRepeatedTest.Create(ATest: ITest; Iterations: integer;
  283.   AName: string);
  284. begin
  285.   inherited Create(ATest, AName);
  286.   FTimesRepeat := Iterations;
  287. end;
  288. function TRepeatedTest.GetHaltOnError: Boolean;
  289. begin
  290.   Result := FHaltOnError;
  291. end;
  292. procedure TRepeatedTest.SetHaltOnError(const Value: Boolean);
  293. begin
  294.   FHaltOnError := Value;
  295. end;
  296. function TRepeatedTest.GetName: string;
  297. begin
  298.   Result := Format('%d x %s', [FTimesRepeat, getTest.Name]);
  299. end;
  300. procedure TRepeatedTest.RunTest(ATestResult: TTestResult);
  301. var
  302.   i: integer;
  303.   ErrorCount: Integer;
  304.   FailureCount: integer;
  305. begin
  306.   assert(assigned(ATestResult));
  307.   ErrorCount := ATestResult.ErrorCount;
  308.   FailureCount := ATestResult.FailureCount;
  309.   for i := 0 to FTimesRepeat - 1 do
  310.   begin
  311.     if ATestResult.shouldStop or
  312.       (Self.HaltOnError and
  313.       ((ATestResult.ErrorCount > ErrorCount) or
  314.        (ATestResult.FailureCount > FailureCount))) then
  315.       Break;
  316.     inherited RunTest(ATestResult);
  317.   end;
  318. end;
  319. { TMemoryTest }
  320. {$IFNDEF CLR}
  321. function TMemoryTest.GetName: string;
  322. begin
  323.   Result := Format('Test memory of %s', [getTest.Name]);
  324. end;
  325. function TMemoryTest.MemoryAllocated: TMemorySize;
  326. begin
  327.   {$IFDEF VER180}
  328.      Result := GetHeapStatus.TotalAllocated;
  329.   {$ELSE}
  330.     {$IFDEF FASTMM}
  331.        Result := FastMM4.FastGetHeapStatus.TotalAllocated;
  332.     {$ELSE}
  333.        {$IFDEF CONDITIONALEXPRESSIONS} // Delphi 6+ or Kylix
  334.          Result := AllocMemSize;
  335.       {$ELSE}
  336.          Result := GetHeapStatus.TotalAllocated;
  337.       {$ENDIF}
  338.     {$ENDIF}
  339.   {$ENDIF}
  340. end;
  341. procedure TMemoryTest.RunTest(ATestResult: TTestResult);
  342. var
  343.   LocalResult :TTestResult;
  344.   Memory      :TMemorySize;
  345. begin
  346.   LocalResult := TTestResult.Create;
  347.   try
  348.     Memory := MemoryAllocated;
  349.     FTest.RunWithFixture(LocalResult);
  350.     Memory := MemoryAllocated - Memory;
  351.     if LocalResult.WasSuccessful then
  352.       CheckEquals(0, Memory, Format('Memory use changed by %d bytes', [Memory]))
  353.     else
  354.       inherited;
  355.   finally
  356.     LocalResult.Free;
  357.   end;
  358. end;
  359. {$ENDIF}
  360. end.