Тестирование в DUnitx с Delphi-Mocks с прохождением частной записи

Я новичок в DUnitx и Delphi-Mocks, поэтому проявите терпение. Единственное сообщение по этой теме, которое я смог найти, было написано 3 года назад, и на него нет ответа. Возврат записей в Delphi-Mocks

Delphi Rio 10.3.Windows 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 вместо ожидаемой проверки Green.

Любая помощь будет оценена. Также правильно ли это использовать Verify? Я могу найти только объяснение, что он ничего не делает при прохождении, так как добавить Assert?

Заранее спасибо Гэри

1 ответ

То, как вы настраиваете макет, будет очень строгим в отношении передаваемых параметров и проверяет соответствие указанной настройке при вызове Verify.

В Delphi Mocks также существует давняя проблема, связанная с тем, что параметры записи не сравниваются должным образом на предмет равенства (они равны, только если параметры имеют один и тот же адрес - см. SameValue в Delphi.Mocks.Helpers.pas- Я знаю об этой проблеме, потому что это мой код, который используется с моего разрешения - некоторое время назад я написал лучшую версию, которая использовалась в Spring4D, в которой также есть фиктивный fwiw). Вот почему, даже если он не будет работать по кругу с вашим добавленнымGetCommandRecord это может не пройти.

То, что я обычно предлагаю людям делать (пока я написал две имитирующие библиотеки для Delphi) при использовании макетов, должно быть максимально разрешительным. К счастью, Delphi Mocks поддерживает сопоставление параметров, которое позволяет указать, что на самом деле вам не так уж важно точное значение передаваемого параметра.

При этом просто измените настройку на вызов

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

Это сообщает внутреннему устройству сопоставления, записывающему вызовы макета из SUT, что не имеет значения, какое значение приходит, какое удовлетворяет ожиданиям.

Кстати по той же причине, что и с SameValue ошибка не будет работать, используя It0.IsEqualTo(LCommandRecord) потому что используемый компаратор для записей внутренне вызывает System.Generics.Defaults.Equals_Binary который просто выполняет сравнение записи с плоской памятью, которая, возможно, не работает для любого ссылочного типа.

Другие вопросы по тегам