【问题标题】:How to test possible memory leaks caused by references after the destruction of the tested object (DUnitX, Spring4D 1.2.2)如何测试被测对象销毁后引用可能导致的内存泄漏(DUnitX、Spring4D 1.2.2)
【发布时间】:2021-12-09 20:05:28
【问题描述】:

TMyClass 包含两个引用。对IList<integer> 的引用和对IMyInterface 的引用。没有必要嘲笑IList<integer>。该框架可能经过良好测试,行为可预测,因此我可以将其视为数据对象。但是IMyInterface 是一个未经测试的服务,所以我应该在单元测试中模拟它。 我想检查内存泄漏,所以我想在主体销毁后测试引用的 RefCount-s 的修改。 IList<integer> 的“RefCount”以正确的方式变化。但我不能对嘲笑的IMyInterface 说同样的话(在我的解决方案中)。我如何测试引用不会导致内存泄漏?或者像这样的测试是集成测试,我应该始终使用真实实例进行测试吗?

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.

【问题讨论】:

  • 请注意,您的getInterfaceRefCount() 采用IInterface 参数按非常量值,因此将在进入时增加其引用计数并在退出时减少其引用计数。因此,返回值将始终是 实际 值的 +1。为避免这种情况,请将参数声明为 const
  • @RemyLebeau 是的。我知道。但我也称它为前后。它适用于真实对象,但不适用于模拟。我将对其进行修改以将其作为 const 传递。
  • 我不是 Spring 方面的专家,但看看这个源代码,IMock&lt;T&gt; 内部有几层代理和拦截器,所以也许你正在测试其中一个内部对象的引用计数而不是实际的IMyInterface 对象?很难说,因为我没有可供测试的 Spring(或工作编译器)。
  • @RemyLebeau 这也是我的想法。这只是一次尝试。我希望 Spring4D 中有一个更好的内置解决方案来捕获内存泄漏。

标签: delphi spring4d dunitx


【解决方案1】:

Memoryleak 检查不需要明确进行 - 我建议使用 https://github.com/shadow-cs/delphi-leakcheck - 它可以与 DUnit 或 DUnitX 无缝集成,并在发生泄漏时自动为您提供所需的所有信息(而不是只告诉您“存在 x 字节泄漏”,开箱即用的 DUnit 只需在运行测试之前和之后比较分配的字节数)

【讨论】:

    猜你喜欢
    • 2014-06-18
    • 1970-01-01
    • 2011-04-17
    • 1970-01-01
    • 2015-12-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-05-12
    相关资源
    最近更新 更多