I'm searching for a way to easily and concisely write a spy for the DUnitX testing framework under Delphi.
In the past, I've used very ugly ways of doing that using :
[TestFixture]
Test = class(TObject)
public
[test]
procedure Test1;
end;
TMyClass = class(TObject)
protected
procedure MyProcedure; virtual;
end;
TMyTestClass = class(TMyClass)
protected
fMyProcedureCalled : Boolean;
procedure MyProcedure; override;
end
procedure TMyTestClass.MyProcedure;
begin
fMyProcedureCalled := true;
inherited;
end;
procedure Test.Test1;
var aObj : TMyTestClass;
begin
TMyTestClass.Create;
Assert.IsTrue(aObj.fMyProcedureCalled);
end;
All of this code to check if a procedure was called. That's too verbose!
Is there a way to write a spy that would help me reduce that code?
Sounds like a use case for a mock (I am using the term mock here because most frameworks refer to their various kinds of test doubles as mock)
In the following example I am using DUnit but it should not make any difference for DUnitX. I am also using the mocking feature from Spring4D 1.2 (I did not check if Delphi Mocks supports this)
unit MyClass;
interface
type
TMyClass = class
private
fCounter: Integer;
protected
procedure MyProcedure; virtual;
public
property Counter: Integer read fCounter;
end;
implementation
procedure TMyClass.MyProcedure;
begin
Inc(fCounter);
end;
end.
program Tests;
uses
TestFramework,
TestInsight.DUnit,
Spring.Mocking,
MyClass in 'MyClass.pas';
type
TMyClass = class(MyClass.TMyClass)
public
// just to make it accessible for the test
procedure MyProcedure; override;
end;
TMyTest = class(TTestCase)
published
procedure Test1;
end;
procedure TMyClass.MyProcedure;
begin
inherited;
end;
procedure TMyTest.Test1;
var
// the mock is getting auto initialized on its first use
// and defaults to TMockBehavior.Dynamic which means it lets all calls happen
m: Mock<TMyClass>;
o: TMyClass;
begin
// set this to true to actually call the "real" method
m.CallBase := True;
// do something with o
o := m;
o.MyProcedure;
// check if the expected call actually did happen
m.Received(Times.Once).MyProcedure;
// to prove that it actually did call the "real" method
CheckEquals(1, o.Counter);
end;
begin
RegisterTest(TMyTest.Suite);
RunRegisteredTests();
end.
Keep in mind though that this only works for virtual methods.