The Wiert Corner – irregular stream of stuff

Jeroen W. Pluimers on .NET, C#, Delphi, databases, and personal interests

  • My badges

  • Twitter Updates

  • My Flickr Stream

  • Pages

  • All categories

  • Enter your email address to subscribe to this blog and receive notifications of new posts by email.

    Join 4,261 other subscribers

Spring4D Mock – Delphi Unit Testing : Writing a simple spy for the CUT – Stack Overflow

Posted by jpluimers on 2020/10/28

Reminder to self: write a longer article on Delphi mocking as Spring4D mocking is much better than Delphi Mocks, especially because of code-completion reasons.

Spring4D has a Mock record that can return a Mock<T> on which you can verify using methods like Received.

See:

I got some code that I need to dig up from an old project with many more Spring4D Mock examples.

Note that:

For now, these are a start [WayBack] Delphi Unit Testing : Writing a simple spy for the CUT – Stack Overflow:

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.

  • In case you need to test a method from a base class which cannot be affected by the $RTTI directive, you can use a little trick and redefine it in subclass in public section as override; abstract; this will cause the RTTI to be generated. – Honza RFeb 5 ’16 at 8:02

–jeroen

Leave a comment

This site uses Akismet to reduce spam. Learn how your comment data is processed.