Home > Net >  How to test possible memory leaks caused by references after the destruction of the tested object (D
How to test possible memory leaks caused by references after the destruction of the tested object (D

Time:01-05

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.

CodePudding user response:

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)

  •  Tags:  
  • Related