* Patch from Graeme Geldenhuys

* Added support for triggering when a TestSuite starts and ends.
  * Modified all the Test Listeners to support the StartTestSuite and
  EndTestSuite interface methods, but only the XML Listener actually
  uses it at the moment.
  * Created a new directory called 'example_xslt' which contains a
  sample XSLT and CSS file. This shows how I convert the generated XML
  data into a HTML page.  (Grouping of the Tests in TestSuites in the
  Test Listing section will follow shortly.)

git-svn-id: trunk@5430 -
This commit is contained in:
michael 2006-11-20 08:23:55 +00:00
parent 2b7fb31a9e
commit dee22e8b4a
4 changed files with 137 additions and 54 deletions

View File

@ -2,11 +2,6 @@
{$IFDEF read_interface} {$IFDEF read_interface}
{
function GetName: string; virtual;
property Name: string read GetName;
}
class procedure Check(pValue: boolean; pMessage: string = ''); class procedure Check(pValue: boolean; pMessage: string = '');
class procedure CheckEquals(expected, actual: extended; msg: string = ''); overload; class procedure CheckEquals(expected, actual: extended; msg: string = ''); overload;
class procedure CheckEquals(expected, actual: string; msg: string = ''); overload; class procedure CheckEquals(expected, actual: string; msg: string = ''); overload;
@ -15,26 +10,24 @@
class procedure CheckEquals(expected, actual: boolean; msg: string = ''); overload; class procedure CheckEquals(expected, actual: boolean; msg: string = ''); overload;
class procedure CheckEquals(expected, actual: TClass; msg: string = ''); overload; class procedure CheckEquals(expected, actual: TClass; msg: string = ''); overload;
class procedure CheckNotEquals(expected, actual: string; msg: string = ''); overload; class procedure CheckNotEquals(expected, actual: string; msg: string = ''); overload;
class procedure CheckNotEquals(expected, actual: integer; msg: string = ''); overload; virtual;
class procedure CheckNotEquals(expected, actual: boolean; msg: string = ''); overload; virtual;
class procedure CheckNotEquals(expected: extended; actual: extended; delta: extended = 0; msg: string = ''); overload; virtual;
class procedure CheckNull(obj: IUnknown; msg: string = ''); overload; class procedure CheckNull(obj: IUnknown; msg: string = ''); overload;
class procedure CheckNull(obj: TObject; msg: string = ''); overload; class procedure CheckNull(obj: TObject; msg: string = ''); overload;
class procedure CheckNotNull(obj: TObject; msg: string = ''); overload; class procedure CheckNotNull(obj: TObject; msg: string = ''); overload;
class procedure CheckIs(obj :TObject; pClass: TClass; msg: string = ''); overload; class procedure CheckIs(obj :TObject; pClass: TClass; msg: string = ''); overload;
class procedure CheckSame(expected, actual: TObject; msg: string = ''); overload; class procedure CheckSame(expected, actual: TObject; msg: string = ''); overload;
class procedure FailNotEquals(expected, actual: string; msg: string = ''; errorAddr: Pointer = nil); virtual;
{ {
*** TODO *** *** TODO ***
procedure CheckEqualsBin(expected, actual: longword; msg: string = ''; digits: integer=32); virtual; procedure CheckEqualsBin(expected, actual: longword; msg: string = ''; digits: integer=32); virtual;
procedure CheckEqualsHex(expected, actual: longword; msg: string = ''; digits: integer=8); virtual; procedure CheckEqualsHex(expected, actual: longword; msg: string = ''; digits: integer=8); virtual;
procedure CheckNotEquals(expected, actual: integer; msg: string = ''); overload; virtual;
procedure CheckNotEquals(expected: extended; actual: extended; delta: extended = 0; msg: string = ''); overload; virtual;
procedure CheckNotEquals(expected, actual: boolean; msg: string = ''); overload; virtual;
procedure CheckNotEqualsBin(expected, actual: longword; msg: string = ''; digits: integer=32); virtual; procedure CheckNotEqualsBin(expected, actual: longword; msg: string = ''; digits: integer=32); virtual;
procedure CheckNotEqualsHex(expected, actual: longword; msg: string = ''; digits: integer=8); virtual; procedure CheckNotEqualsHex(expected, actual: longword; msg: string = ''; digits: integer=8); virtual;
procedure CheckNotNull(obj :IUnknown; msg :string = ''); overload; virtual; procedure CheckNotNull(obj :IUnknown; msg :string = ''); overload; virtual;
procedure CheckSame(expected, actual: IUnknown; msg: string = ''); overload; virtual; procedure CheckSame(expected, actual: IUnknown; msg: string = ''); overload; virtual;
procedure CheckException(AMethod: TTestMethod; AExceptionClass: TClass; msg :string = ''); procedure CheckException(AMethod: TTestMethod; AExceptionClass: TClass; msg :string = '');
procedure CheckInherits(expected, actual: TClass; msg: string = ''); overload; virtual; procedure CheckInherits(expected, actual: TClass; msg: string = ''); overload; virtual;
} }
@ -44,81 +37,82 @@
{$IFDEF read_implementation} {$IFDEF read_implementation}
{
function TAssert.GetName: string;
begin
Result := TestName;
end;
}
class procedure TAssert.Check(pValue: boolean; pMessage: string); class procedure TAssert.Check(pValue: boolean; pMessage: string);
begin begin
AssertTrue(pMessage, pValue); AssertTrue(pMessage, pValue);
end; end;
class procedure TAssert.CheckEquals(expected, actual: extended; msg: string); class procedure TAssert.CheckEquals(expected, actual: extended; msg: string);
begin begin
AssertEquals(msg, expected, actual); AssertEquals(msg, expected, actual);
end; end;
class procedure TAssert.CheckEquals(expected, actual: string; msg: string); class procedure TAssert.CheckEquals(expected, actual: string; msg: string);
begin begin
AssertEquals(msg, expected, actual); AssertEquals(msg, expected, actual);
end; end;
class procedure TAssert.CheckEquals(expected, actual: extended; class procedure TAssert.CheckEquals(expected, actual: extended;
delta: extended; msg: string); delta: extended; msg: string);
begin begin
AssertEquals(msg, expected, actual, delta); AssertEquals(msg, expected, actual, delta);
end; end;
class procedure TAssert.CheckEquals(expected, actual: integer; msg: string); class procedure TAssert.CheckEquals(expected, actual: integer; msg: string);
begin begin
AssertEquals(msg, expected, actual); AssertEquals(msg, expected, actual);
end; end;
class procedure TAssert.CheckEquals(expected, actual: boolean; msg: string); class procedure TAssert.CheckEquals(expected, actual: boolean; msg: string);
begin begin
AssertEquals(msg, expected, actual); AssertEquals(msg, expected, actual);
end; end;
class procedure TAssert.CheckEquals(expected, actual: TClass; msg: string); class procedure TAssert.CheckEquals(expected, actual: TClass; msg: string);
begin begin
AssertEquals(msg, expected, actual); AssertEquals(msg, expected, actual);
end; end;
class procedure TAssert.CheckNotEquals(expected, actual: string; msg: string); class procedure TAssert.CheckNotEquals(expected, actual: string; msg: string);
begin begin
if AnsiCompareStr(Expected, Actual) = 0 then if AnsiCompareStr(Expected, Actual) = 0 then
Fail(msg + ComparisonMsg(Expected, Actual)); Fail(msg + ComparisonMsg(Expected, Actual));
end; end;
class procedure TAssert.CheckNotEquals(expected, actual: integer; msg: string);
begin
if (expected = actual) then
Fail(msg + ComparisonMsg(IntToStr(expected), IntToStr(actual)));
end;
class procedure TAssert.CheckNotEquals(expected, actual: boolean; msg: string);
begin
if (expected = actual) then
Fail(msg + ComparisonMsg(BoolToStr(expected), BoolToStr(actual)));
end;
class procedure TAssert.CheckNotEquals(expected: extended; actual: extended;
delta: extended; msg: string);
begin
if (abs(expected-actual) <= delta) then
FailNotEquals(FloatToStr(expected), FloatToStr(actual), msg, nil);
end;
class procedure TAssert.CheckNull(obj: IUnknown; msg: string); class procedure TAssert.CheckNull(obj: IUnknown; msg: string);
begin begin
AssertNullIntf(msg, obj); AssertNullIntf(msg, obj);
end; end;
class procedure TAssert.CheckNull(obj: TObject; msg: string); class procedure TAssert.CheckNull(obj: TObject; msg: string);
begin begin
AssertNull(msg, obj); AssertNull(msg, obj);
end; end;
class procedure TAssert.CheckNotNull(obj: TObject; msg: string); class procedure TAssert.CheckNotNull(obj: TObject; msg: string);
begin begin
AssertNotNull(msg, obj); AssertNotNull(msg, obj);
end; end;
class procedure TAssert.CheckIs(obj: TObject; pClass: TClass; msg: string); class procedure TAssert.CheckIs(obj: TObject; pClass: TClass; msg: string);
begin begin
Assert(pClass <> nil); Assert(pClass <> nil);
@ -128,11 +122,16 @@ begin
Fail(ComparisonMsg(pClass.ClassName, obj.ClassName)); Fail(ComparisonMsg(pClass.ClassName, obj.ClassName));
end; end;
class procedure TAssert.CheckSame(expected, actual: TObject; msg: string); class procedure TAssert.CheckSame(expected, actual: TObject; msg: string);
begin begin
AssertSame(msg, expected, actual); AssertSame(msg, expected, actual);
end; end;
class procedure TAssert.FailNotEquals(expected, actual: string; msg: string;
errorAddr: Pointer);
begin
Fail(msg + ComparisonMsg(Expected, Actual));
end;
{$ENDIF read_implementation} {$ENDIF read_implementation}

View File

@ -57,6 +57,7 @@ type
TRunMethod = procedure of object; TRunMethod = procedure of object;
TTestResult = class; TTestResult = class;
TTestSuite = class;
{$M+} {$M+}
TTest = class(TObject) TTest = class(TObject)
@ -80,6 +81,8 @@ type
{$M-} {$M-}
{ TAssert }
TAssert = class(TTest) TAssert = class(TTest)
public public
class procedure Fail(const AMessage: string); class procedure Fail(const AMessage: string);
@ -170,6 +173,8 @@ type
procedure AddError(ATest: TTest; AError: TTestFailure); procedure AddError(ATest: TTest; AError: TTestFailure);
procedure StartTest(ATest: TTest); procedure StartTest(ATest: TTest);
procedure EndTest(ATest: TTest); procedure EndTest(ATest: TTest);
procedure StartTestSuite(ATestSuite: TTestSuite);
procedure EndTestSuite(ATestSuite: TTestSuite);
end; end;
TTestCase = class(TAssert) TTestCase = class(TAssert)
@ -271,6 +276,8 @@ type
function SkipTest(ATestCase: TTestCase): boolean; function SkipTest(ATestCase: TTestCase): boolean;
procedure AddToSkipList(ATestCase: TTestCase); procedure AddToSkipList(ATestCase: TTestCase);
procedure RemoveFromSkipList(ATestCase: TTestCase); procedure RemoveFromSkipList(ATestCase: TTestCase);
procedure StartTestSuite(ATestSuite: TTestSuite);
procedure EndTestSuite(ATestSuite: TTestSuite);
published published
property Listeners: TFPList read FListeners; property Listeners: TFPList read FListeners;
property Failures: TFPList read FFailures; property Failures: TFPList read FFailures;
@ -1005,8 +1012,14 @@ procedure TTestSuite.Run(AResult: TTestResult);
var var
i: integer; i: integer;
begin begin
if FTests.Count > 0 then
AResult.StartTestSuite(self);
for i := 0 to FTests.Count - 1 do for i := 0 to FTests.Count - 1 do
RunTest(TTest(FTests[i]), AResult); RunTest(TTest(FTests[i]), AResult);
if FTests.Count > 0 then
AResult.EndTestSuite(self);
end; end;
@ -1247,5 +1260,21 @@ begin
FSkippedTests.Remove(ATestCase); FSkippedTests.Remove(ATestCase);
end; end;
procedure TTestResult.StartTestSuite(ATestSuite: TTestSuite);
var
i: integer;
begin
for i := 0 to FListeners.Count - 1 do
ITestListener(FListeners[i]).StartTestSuite(ATestSuite);
end;
procedure TTestResult.EndTestSuite(ATestSuite: TTestSuite);
var
i: integer;
begin
for i := 0 to FListeners.Count - 1 do
ITestListener(FListeners[i]).EndTestSuite(ATestSuite);
end;
end. end.

View File

@ -22,6 +22,9 @@ uses
classes, SysUtils, fpcunit, testutils; classes, SysUtils, fpcunit, testutils;
type type
{ TXMLResultsWriter }
TXMLResultsWriter = class(TNoRefCountObject, ITestListener) TXMLResultsWriter = class(TNoRefCountObject, ITestListener)
public public
procedure WriteHeader; procedure WriteHeader;
@ -31,8 +34,12 @@ type
procedure AddError(ATest: TTest; AError: TTestFailure); procedure AddError(ATest: TTest; AError: TTestFailure);
procedure StartTest(ATest: TTest); procedure StartTest(ATest: TTest);
procedure EndTest(ATest: TTest); procedure EndTest(ATest: TTest);
procedure StartTestSuite(ATestSuite: TTestSuite);
procedure EndTestSuite(ATestSuite: TTestSuite);
end; end;
{ TPlainResultsWriter }
TPlainResultsWriter = class(TNoRefCountObject, ITestListener) TPlainResultsWriter = class(TNoRefCountObject, ITestListener)
public public
procedure WriteHeader; procedure WriteHeader;
@ -42,6 +49,8 @@ type
procedure AddError(ATest: TTest; AError: TTestFailure); procedure AddError(ATest: TTest; AError: TTestFailure);
procedure StartTest(ATest: TTest); procedure StartTest(ATest: TTest);
procedure EndTest(ATest: TTest); procedure EndTest(ATest: TTest);
procedure StartTestSuite(ATestSuite: TTestSuite);
procedure EndTestSuite(ATestSuite: TTestSuite);
end; end;
{ {
@ -51,6 +60,8 @@ type
procedure AddError(ATest: TTest; AError: TTestFailure); procedure AddError(ATest: TTest; AError: TTestFailure);
procedure StartTest(ATest: TTest); procedure StartTest(ATest: TTest);
procedure EndTest(ATest: TTest); procedure EndTest(ATest: TTest);
procedure StartTestSuite(ATestSuite: TTestSuite);
procedure EndTestSuite(ATestSuite: TTestSuite);
end;} end;}
function TestSuiteAsXML(aSuite:TTestSuite; Indent : Integer): string; function TestSuiteAsXML(aSuite:TTestSuite; Indent : Integer): string;
@ -106,6 +117,16 @@ begin
writeln('</test>'); writeln('</test>');
end; end;
procedure TXMLResultsWriter.StartTestSuite(ATestSuite: TTestSuite);
begin
end;
procedure TXMLResultsWriter.EndTestSuite(ATestSuite: TTestSuite);
begin
end;
{TPlainResultsWriter} {TPlainResultsWriter}
procedure TPlainResultsWriter.WriteHeader; procedure TPlainResultsWriter.WriteHeader;
begin begin
@ -132,7 +153,7 @@ end;
procedure TPlainResultsWriter.StartTest(ATest: TTest); procedure TPlainResultsWriter.StartTest(ATest: TTest);
begin begin
write('Test: ' , ATest.TestSuiteName + '.' + ATest.TestName); write('Test: ', ATest.TestSuiteName + '.' + ATest.TestName);
end; end;
procedure TPlainResultsWriter.EndTest(ATest: TTest); procedure TPlainResultsWriter.EndTest(ATest: TTest);
@ -140,6 +161,18 @@ begin
writeln; writeln;
end; end;
procedure TPlainResultsWriter.StartTestSuite(ATestSuite: TTestSuite);
begin
{ example output }
// Writeln('TestSuite: ' + ATestSuite.TestName);
end;
procedure TPlainResultsWriter.EndTestSuite(ATestSuite: TTestSuite);
begin
{ example output }
// Writeln('TestSuite: ' + ATestSuite.TestName + ' - END ');
end;
function TestSuiteAsXML(aSuite:TTestSuite): string; function TestSuiteAsXML(aSuite:TTestSuite): string;
begin begin

View File

@ -22,7 +22,7 @@
framework. It uses the XMLWrite unit, which is part of FPC, to generate framework. It uses the XMLWrite unit, which is part of FPC, to generate
the XML document. The benefit of using the XMLWrite unit, is that the the XML document. The benefit of using the XMLWrite unit, is that the
data generated is valid XML, with resevered characters correctly escaped. data generated is valid XML, with resevered characters correctly escaped.
This allows the XML document to be further processed with XSTL etc without This allows the XML document to be further processed with XSLT etc without
any issues. any issues.
} }
@ -44,6 +44,9 @@ uses
type type
{ XML Test Listner } { XML Test Listner }
{ TXMLResultsWriter }
TXMLResultsWriter = class(TNoRefCountObject, ITestListener) TXMLResultsWriter = class(TNoRefCountObject, ITestListener)
private private
FDoc: TXMLDocument; FDoc: TXMLDocument;
@ -53,6 +56,7 @@ type
FFailures: TDOMNode; FFailures: TDOMNode;
FIgnores: TDOMNode; FIgnores: TDOMNode;
FErrors: TDOMNode; FErrors: TDOMNode;
FLastTestSuite: TDOMNode;
FStartCrono: TDateTime; FStartCrono: TDateTime;
{ Converts the actual test results into XML nodes. This gets called { Converts the actual test results into XML nodes. This gets called
by the public method WriteResult. } by the public method WriteResult. }
@ -69,7 +73,9 @@ type
procedure AddError(ATest: TTest; AError: TTestFailure); procedure AddError(ATest: TTest; AError: TTestFailure);
procedure StartTest(ATest: TTest); procedure StartTest(ATest: TTest);
procedure EndTest(ATest: TTest); procedure EndTest(ATest: TTest);
procedure StartTestSuite(ATestSuite: TTestSuite);
procedure EndTestSuite(ATestSuite: TTestSuite);
{ A public property to the internal XML document } { A public property to the internal XML document }
property Document: TXMLDocument read FDoc; property Document: TXMLDocument read FDoc;
end; end;
@ -125,18 +131,25 @@ end;
constructor TXMLResultsWriter.Create; constructor TXMLResultsWriter.Create;
begin begin
FDoc := TXMLDocument.Create; FDoc := TXMLDocument.Create;
FResults := nil; FResults := nil;
FFailures := nil; FFailures := nil;
FIgnores := nil; FIgnores := nil;
FErrors := nil; FErrors := nil;
FListing := nil; FListing := nil;
FLastTestSuite := nil;
WriteHeader; WriteHeader;
end; end;
destructor TXMLResultsWriter.Destroy; destructor TXMLResultsWriter.Destroy;
begin begin
FResults := nil;
FFailures := nil;
FIgnores := nil;
FErrors := nil;
FListing := nil;
FLastTestSuite := nil;
FDoc.Free; FDoc.Free;
inherited Destroy; inherited Destroy;
end; end;
@ -218,19 +231,9 @@ procedure TXMLResultsWriter.StartTest(ATest: TTest);
var var
n: TDOMElement; n: TDOMElement;
begin begin
{ Try and find the Listings node first }
if not Assigned(FListing) then
FListing := FDoc.FindNode('TestListing');
{ If we couldn't find it, create it }
if not Assigned(FListing) then
begin
FListing := FDoc.CreateElement('TestListing');
FResults.AppendChild(FListing);
end;
n := FDoc.CreateElement('Test'); n := FDoc.CreateElement('Test');
n['Name'] := ATest.TestSuiteName + '.' + ATest.TestName; n['Name'] := ATest.TestSuiteName + '.' + ATest.TestName;
FListing.AppendChild(n); FLastTestSuite.AppendChild(n);
FStartCrono := Now; FStartCrono := Now;
end; end;
@ -239,6 +242,16 @@ procedure TXMLResultsWriter.EndTest(ATest: TTest);
var var
n: TDOMNode; n: TDOMNode;
lNew: TDOMElement; lNew: TDOMElement;
begin
n := FLastTestSuite.LastChild;
lNew := FDoc.CreateElement('ElapsedTime');
lNew.AppendChild(FDoc.CreateTextNode(FormatDateTime('hh:nn:ss.zzz', Now - FStartCrono)));
n.AppendChild(lNew);
end;
procedure TXMLResultsWriter.StartTestSuite(ATestSuite: TTestSuite);
var
n: TDOMElement;
begin begin
{ Try and find the Listings node first } { Try and find the Listings node first }
if not Assigned(FListing) then if not Assigned(FListing) then
@ -250,10 +263,19 @@ begin
FResults.AppendChild(FListing); FResults.AppendChild(FListing);
end; end;
n := FListing.LastChild; { The first TestSuite always seem to be blank/empty }
lNew := FDoc.CreateElement('ElapsedTime'); if ATestSuite.TestName <> '' then
lNew.AppendChild(FDoc.CreateTextNode(FormatDateTime('hh:nn:ss.zzz', Now - FStartCrono))); begin
n.AppendChild(lNew); n := FDoc.CreateElement('TestSuite');
n['Name'] := ATestSuite.TestName;
FListing.AppendChild(n);
FLastTestSuite := n;
end;
end;
procedure TXMLResultsWriter.EndTestSuite(ATestSuite: TTestSuite);
begin
// do nothing
end; end;