2

我是 DUnitx 和 Delphi-Mocks 的新手,所以请耐心等待。我能找到的关于这个主题的唯一其他帖子是 3 岁且没有回答。在 Delphi-Mocks 中返回记录

德尔福里约 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;

在我的测试项目中,我有一个后代类

 TTestabledmMariaDBConnection = class(TdmMariaDBConnection)
  end;
var
  CUT : TTestabledmMariaDBConnection;

procedure TTestModel_MariaDBConnection.Setup;
begin
  CUT := TTestabledmMariaDBConnection.Create(nil);
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;

显然添加 LCommandRecord 是错误的,我只是添加它们以使其编译。我需要(我认为)设置中测试类的记录实例。我尝试添加一个函数来获得它,但它也不起作用。

function TdmMariaDBConnection.GetCommandRecord: TPsCommandRecord;
begin
  Result := FCommandRecord;
end;

MVMMock.Setup.Expect.Once.When.HandleCommands(CUT.GetCommandRecord);

测试甚至没有完成,我在 TestInsight GUI 中得到一个不完整的圆圈,而不是希望的绿色检查。

任何帮助,将不胜感激。这也是验证的正确用法吗?我只能找到通过时什么都不做的解释,那么如何添加Assert?

提前感谢加里

4

1 回答 1

1

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

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

在使用模拟时,我通常建议人们做的事情(到目前为止,我为 Delphi 编写了 2 个模拟库)是尽可能宽容。幸运的是,Delphi Mocks 支持参数匹配器,让您可以指定实际上您并不关心传递的参数的确切值。

话虽这么说,只需将您的设置更改为调用

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

这告诉内部匹配器记录从 SUT 对模拟的调用,无论哪个值满足期望都无关紧要。

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

于 2020-01-24T17:09:13.940 回答