2

我正在执行单元测试的类滚动数据库表的每条记录,并将字段中的值与前一个值相加。以下是简化为骨骼的类:

procedure TSumList.Sum;
var
  FSum:integer;
begin
  FSum:=0;
  FDB.First;
  while not FDB.EOF do
  begin
    FSum:=FSum+FDB.GetAmount;
    FDB.Next;
  end;
end;

FDB 指的是名为 IIDBTable 的 DB 模拟接口。

以下是依赖注入的数据库模拟:

  IIDBTable = interface
    ['{A299D1D6-93AF-45CC-8DE2-9A4EE188C352}']
    procedure First;
    procedure Next;
    function EOF : boolean;
    function GetAmount:integer;
  end;

  TMockDBTable = class (TInterfacedObject,IDBTable)
    procedure First;
    procedure Next;
    function EOF : boolean;
    function GetAmount:integer;
  end;

问题是我不知道如何为模拟提供数据以进行测试。当然,我可以添加一个额外的过程,比如 AddValues(aAmount:integer),它可以完成这项工作,但在这种情况下,我最终也会在生产中使用这个额外的过程,我不需要它。

对此的最佳做法是什么?

我使用 Spring for Delphi 框架

4

2 回答 2

4

您还可以使用 DSharp 模拟(或 Delphi 模拟)。

这将是 DSharp 的设置代码(Delphi Mocks 应该类似)

var
  mockDBTable: Mock<IIDBTable>;
begin
  mockDBTable.Setup.WillExecute.Once.WhenCalling.First;
  mockDBTable.Setup.WillReturn(False).Exactly(5).WhenCalling.EOF;
  mockDBTable.Setup.WillReturn(True).Once.WhenCalling.EOF;
  mockDBTable.Setup.WillReturn(5).Once.WhenCalling.GetAmount;
  mockDBTable.Setup.WillReturn(4).Once.WhenCalling.GetAmount;
  mockDBTable.Setup.WillReturn(3).Once.WhenCalling.GetAmount;
  mockDBTable.Setup.WillReturn(2).Once.WhenCalling.GetAmount;
  mockDBTable.Setup.WillReturn(1).Once.WhenCalling.GetAmount;
  mockDBTable.Setup.WillExecute.Exactly(5).WhenCalling.Next;

您在这里所做的是指定您希望调用的内容和返回的内容。这使您免于手动编写模拟类并为其提供数据。

于 2014-02-04T07:53:43.323 回答
2

向模拟类添加一个额外的方法,AddValues. 它只存在于该模拟类中,而不存在于真实类中,因此您反对额外代码出现在生产中是没有根据的。

我怀疑您认为代码需要投入生产,因为您只通过接口处理模拟对象。额外的方法将存在于接口中,因此需要在类的生产版本中实现,即使它不属于那里。

相反,实例化TMockDBTable并通过对象引用访问它以设置它,但它是测试所需的。一旦准备好,然后IIDBTable通过界面切换到使用它。

另一种选择是通过添加到其构造函数的参数将数据馈送到类中。然后你甚至不需要额外的方法,因此没有在接口或生产类上定义该方法的诱惑。没有理由你的模拟类的构造函数需要看起来像生产类的构造函数,因为这些类根本不相关。构造函数不是接口定义的一部分。

于 2014-02-03T22:32:31.167 回答