在DUnitx中测试,Delphi模拟通过私有记录

在DUnitx中测试,Delphi模拟通过私有记录,delphi,testing,delphi-mocks,Delphi,Testing,Delphi Mocks,我是DUnitx和Delphi Mocks的新手,请耐心等待。我能找到的关于这个话题的其他帖子只有3年了,没有得到回复 Delphi Rio 10.3。 视窗10 我想测试这个过程: procedure TdmMariaDBConnection.Notify; var LViewModel : IPsViewModel; begin FMainViewModel.HandleCommands(FCommandRecord); for LViewModel in FObservers

我是DUnitx和Delphi Mocks的新手,请耐心等待。我能找到的关于这个话题的其他帖子只有3年了,没有得到回复

Delphi Rio 10.3。 视窗10

我想测试这个过程:

procedure TdmMariaDBConnection.Notify;
var
  LViewModel : IPsViewModel;
begin
  FMainViewModel.HandleCommands(FCommandRecord);
  for LViewModel in FObservers do
    LViewModel.HandleCommands(FCommandRecord);
end;
接口和记录类型声明为:

    IPsView = interface(IInvokable)
        ['{F5532762-09F8-42C4-9F9F-A8F7FF7FA0C6}']
        procedure HandleCommands(const Value: TPsCommandRecord);
        procedure AfterCreate;
        procedure BeforeDestroy;
      end;

      IPsViewModel = interface(IInvokable)
        ['{322DAB08-6A7C-4B61-B656-BC5346ACFC14}']
        procedure HandleCommands(const Value: TPsCommandRecord);
      end;

      IPsMainViewModel = interface(IInvokable)
        ['{98FFB416-6C22-492F-BC85-D9A1ECA667FE}']
        procedure Attach(const observer: IPsView);
        procedure Notify;
        procedure LoadFrame(const Value: TPanel);
        procedure LoadForm(const Value: integer);
        procedure LoadModalForm(const Value: integer);
        procedure HandleCommands(const Value: TPsCommandRecord);
        procedure SetViewFactory(Value: IPsViewFactory);
        property ViewFactory: IPsViewFactory write SetViewFactory;
      end;

  TPsCommandRecord = record
    CommandType: integer;
    CommandObject: TObject;
    CommandMessage: TPsTaskDialogMessageRecord;
  end;
我在受保护部分有通知程序

type
  TdmMariaDBConnection = class(TDataModule, IPsModel)
    procedure DataModuleDestroy(Sender: TObject);
    procedure DataModuleCreate(Sender: TObject);
  private
    FObservers : TList<IPsViewModel>;
    FMainViewModel : IPsMainViewModel;
    FCommandRecord : TPsCommandRecord;
  protected
    procedure Notify;
  ….
end;
所以我可以调用受保护的方法。到目前为止,我所拥有的不起作用,因为我无法从TdmMariaDBConnection提供私有记录实例,现在只关注MainViewModel

procedure TTestModel_MariaDBConnection.NotifyCallsMainViewModelHandleCommands;
var
  MVMMock : TMock<IPsMainViewModel>;
  LCommandRecord : TPsCommandRecord;
begin
  //Arrange
  MVMMock := TMock<IPsMainViewModel>.Create;
  MVMMock.Setup.Expect.Once.When.HandleCommands(LCommandRecord);
  //Act
   CUT.Attach(MVMMock);
   CUT.Notify;
  //Assert
  try
    MVMMock.Verify();
    Assert.Pass();
  except on E: EMockException do
    Assert.Fail(E.Message);
  end;
end;
测试甚至没有完成,我在TestInsight GUI中得到了一个不完整的圆圈,而不是希望的绿色检查

任何帮助都将不胜感激。这也是验证的正确用法吗?我只能找到这样的解释,即它在传递时不做任何事情,那么如何添加断言呢

提前谢谢
Gary

在调用Verify时,设置模拟的方式将对传递的参数非常严格,并检查与指定设置的相等性

Delphi模拟中还有一个长期存在的问题,即记录参数没有正确地进行相等性比较(只有当参数的地址完全相同时,它们才相等-请参见
Delphi.Mocks.Helpers.pas中的
SameValue
-我知道这个问题,因为我的代码是在我的许可下使用的-我不久前在Spring4D中编写了一个更好的版本,它也有mocking fwiw)。这就是为什么即使它不会与您添加的
GetCommandRecord
一起在一个圆圈中运行,它也可能不会通过

我通常建议人们在使用mocks时(到目前为止,我为Delphi编写了两个mocking库)要尽可能地允许。幸运的是,Delphi mocks支持参数匹配器,允许您指定实际上您并不太关心所传递参数的确切值

也就是说,只需将设置更改为调用

MVMMock.Setup.Expect.Once.When.HandleCommands(It0.IsAny<TPsCommandRecord>);
MVMMock.Setup.Expect.one.When.handleCommand(It0.IsAny);
这告诉记录来自SUT的模拟调用的内部匹配器,满足预期的值并不重要


顺便说一句,由于与
SameValue
bug类似的原因,使用
It0.IsEqualTo(LCommandRecord)将无法工作
因为用于记录的比较器在内部调用了
System.Generics.Defaults.Equals\u Binary
,它只对记录进行平面内存比较,对于任何引用类型都可能失败。

谢谢,这就成功了。你会推荐使用Spring4D而不是Delphi Mocks吗?作为Spring4D的维护者,我有点偏见,但是Delphi Mocks最近很少受到关注(看起来是这样),而且我的mocking库中不存在一些问题(两个库中都存在一些问题,这是由于Delphi RTTI中的缺陷造成的)。它们的工作方式有点不同,因为Spring4D Mocks更受Moq的启发。我想说,尝试一下,然后决定您更喜欢哪个。
function TdmMariaDBConnection.GetCommandRecord: TPsCommandRecord;
begin
  Result := FCommandRecord;
end;

MVMMock.Setup.Expect.Once.When.HandleCommands(CUT.GetCommandRecord);
MVMMock.Setup.Expect.Once.When.HandleCommands(It0.IsAny<TPsCommandRecord>);