delphispring4ddunitx

How to test possible memory leaks caused by references after the destruction of the tested object (DUnitX, Spring4D 1.2.2)


TMyClass contains two references. A reference to an IList<integer> and a reference to IMyInterface. The mocking of IList<integer> is not necessary. The framework probably well tested, well predictable behavior, so I could see it as a Data object. But IMyInterface is an untested service, so I should mock it in a unit test. I want to check for memory leaks so I want to test the modifications of the RefCount-s of the references after the subject destroyed. The 'RefCount' of the IList<integer> changes in the right way. But I can't say the same for the mocked IMyInterface (in my solution). How could I test that the references does not cause memory leaks? Or a test like this is an integration test and should I test it always with real instances?

unit Unit1;


interface

uses
    DUnitX.TestFramework
  , Spring.Collections
  , Spring.Mocking
  ;

type
IMyInterface = interface ( IInvokable )
  ['{76B13784-6CCF-4A87-882C-E624F003B082}']
  procedure foo;
end;

TMyClass = class
  private
    fList : IList<integer>;
    fMyInterface : IMyInterface;

  public
    constructor Create( list_ : IList<integer>; myInterface_ : IMyInterface );

end;

[TestFixture]
TMyClassTest = class
  protected
    function getInterfaceRefCount( const interface_ : IInterface ) : integer;

  public
    [Test]
    procedure listRefCountTest;
    [Test]
    procedure myInterfaceRefCountTest;

end;

implementation

uses
  System.SysUtils
  ;

constructor TMyClass.Create( list_ : IList<integer>; myInterface_ : IMyInterface );
begin
  inherited Create;
  fList := list_;
  fMyInterface := myInterface_;
end;

function TMyClassTest.getInterfaceRefCount( const interface_ : IInterface ) : integer;
begin
  result := ( interface_ as TInterfacedObject ).RefCount;
end;

procedure TMyClassTest.listRefCountTest;
var
  list : IList<integer>;
  myInterfaceMock : Mock<IMyInterface>;
  myClass : TMyClass;
  listRefCount : integer;
begin
  list := TCollections.CreateList<integer>;
  myClass := TMyClass.Create( list, myInterfaceMock );
  try
    listRefCount := getInterfaceRefCount( list );
  finally
    FreeAndNIL( myClass );
  end;
  Assert.AreEqual( listRefCount-1, getInterfaceRefCount( list ) );
end;

procedure TMyClassTest.myInterfaceRefCountTest;
var
  list : IList<integer>;
  myInterfaceMock : Mock<IMyInterface>;
  myClass : TMyClass;
  myInterfaceRefCount : integer;
begin
  list := TCollections.CreateList<integer>;
  myClass := TMyClass.Create( list, myInterfaceMock );
  try
    myInterfaceRefCount := getInterfaceRefCount( myInterfaceMock.Instance );
  finally
    FreeAndNIL( myClass );
  end;
  Assert.AreEqual( myInterfaceRefCount-1, getInterfaceRefCount( myInterfaceMock.Instance ) );
end;

initialization
  TDUnitX.RegisterTestFixture(TMyClassTest);

end.

Solution

  • Memoryleak checking does not need to be done explicitly - I suggest using https://github.com/shadow-cs/delphi-leakcheck for that - it can seemlessly integrated with either DUnit or DUnitX and automatically provides you with all the information you need when a leak occurs (opposed to only telling you "there was a leak of x bytes" which out of the box DUnit does by simply comparing allocated bytes before and after running the test)