0

使用简单数据类型或对象时,带有 Delphi 2010 的 PascalMock 可以正常工作。然而,有了记录,就有了麻烦。

TMock.Returns需要一个数组TVarRec,所以我不能只传入一个。

有一个将其转换为指针的示例,但由于它代表一个值,这对我来说没有意义。当该记录将在某些函数之间传递时,最后我将取回具有不同地址的副本。

我尝试的另一件事是将字节级别的记录复制到Variantusing 中VarArrayCreate。当馈送到 PascalMock 时,这神秘地导致错误转换为整数。当我刚刚传入时,我得到了同样的错误Variant(TBytes.Create(1, 2, 3))。没有明确的情况 to Variant,我再次得到一个整数(指针?)。

当然,我总是可以完全手动编写一个模拟,但考虑到 PascalMock 的年龄,我希望这是一个已解决的问题。请注意,我什至没有使用最新AutoMockIntf添加的内容。是否有适当的方法将任何记录转换为 PascalMocks 可以使用的 Variant 或从 Variant 转换?或者在这种情况下是否有更好的方法来处理记录?

这是我想要实现的一些示例代码:

interface

uses
  SysUtils,
  TestFramework,
  PascalMock;

type
  TMyRecord = record
    // Sample fields but should work for any record structure
    FirstField: Integer;
    SecondField: string;
    class operator Equal(const A, B: TMyRecord): Boolean;
    class operator NotEqual(const A, B: TMyRecord): Boolean;
  end;

  IRecordMaker = interface
  ['{436D6FC3-3DCD-4EFF-B206-1C3E1A5561D1}']
    function Make: TMyRecord;
  end;

  TFakeRecordMaker = class(TMock, IRecordMaker)
  public
    function Make: TMyRecord;
  end;

  IRecordSaver = interface
  ['{91BB1347-A34E-4A77-8993-3ADBFBE8726D}']
    procedure Save(const ARecord: TMyRecord);
  end;

  TFakeRecordSaver = class(TMock, IRecordSaver)
  public
    procedure Save(const ARecord: TMyRecord);
  end;

  TRunner = class
  private
    FRecordMaker: IRecordMaker;
    FRecordSaver: IRecordSaver;
  public
    constructor Create(ARecordMaker: IRecordMaker; ARecordSaver: IRecordSaver);
    procedure Run;
  end;

  TestRunner = class(TTestCase)
  private
    FRecordMaker: TFakeRecordMaker;
    FRecordSaver: TFakeRecordSaver;
  protected
    procedure SetUp; override;
    procedure TearDown; override;
  published
    procedure MakesRecordAndSavesIt;
  end;

implementation

{ TMyRecord }

class operator TMyRecord.Equal(const A, B: TMyRecord): Boolean;
begin
  Result := (A.FirstField = B.FirstField) and (A.SecondField = B.SecondField);
end;

class operator TMyRecord.NotEqual(const A, B: TMyRecord): Boolean;
begin
  Result := not (A = B);
end;

{ TFakeRecordMaker }

function TFakeRecordMaker.Make: TMyRecord;
begin
  // Remember having been called and return the desired data
  Result := AddCall('Make').ReturnValue;
end;

{ TFakeRecordSaver }

procedure TFakeRecordSaver.Save(const ARecord: TMyRecord);
begin
  // Remember having been called and with what arguments
  AddCall('Save').WithParams([ARecord]);
end;

{ TRunner }

constructor TRunner.Create(ARecordMaker: IRecordMaker; ARecordSaver: IRecordSaver);
begin
  inherited Create;
  FRecordMaker := ARecordMaker;
  FRecordSaver := ARecordSaver;
end;

procedure TRunner.Run;
var
  LRecord: TMyRecord;
begin
  LRecord := FRecordMaker.Make;
  FRecordSaver.Save(LRecord);
end;

{ TestRunner }

procedure TestRunner.SetUp;
begin
  inherited;
  FRecordMaker := TFakeRecordMaker.Create;
  FRecordSaver := TFakeRecordSaver.Create;
end;

procedure TestRunner.MakesRecordAndSavesIt;
var
  LRecord: TMyRecord;
  LSUT: TRunner;
begin
  // The test data
  LRecord.FirstField := 3;
  LRecord.SecondField := 'bla';
  // The first collaborator serving as stub should return this data
  FRecordMaker.Expects('Make').Returns(LRecord);
  // The second collaborator serving as mock should be passed this data
  FRecordSaver.Expects('Save').WithParams([LRecord]);
  LSUT := TRunner.Create(FRecordMaker, FRecordSaver);
  try
    // Hopefully the SUT will get the data and pass it on
    LSUT.Run;
    // Check if the remembered calls match the expected ones
    FRecordSaver.Verify;
  finally
    LSUT.Free;
  end;
end;

procedure TestRunner.TearDown;
begin
  FRecordSaver.Free;
  FRecordMaker.Free;
  inherited;
end;

initialization
  RegisterTest(TestRunner.Suite);

end.
4

0 回答 0