如何模拟没有虚方法的类?

时间:2011-05-02 20:52:55

标签: delphi unit-testing mocking

假设您有一个设计精良的Delphi项目,该项目尊重依赖注入和其他一些良好实践。

现在让我们假设你需要模拟一个定义为:

的类
TMyClass = class
public
  procedure Method1;
  procedure Method2
end;  

Method1Method2不是虚拟的。在这种情况下你做什么?要模拟对象,我们需要继承它并override要模拟的每个方法,但在这种情况下不可能因为它们不是virtual。我是否应该更改源代码以在我需要模拟的每个方法上添加virtual?不是很糟糕吗?

修改

我正在考虑创建一个编译器指令,使类中的所有字段都为virtual,这是一个很好的意识形态吗?只有我的测试套件才会设置编译器指令。

EDIT2 *

Embarcadero应该提供一种简单的方法,可以将类的方法指针更改为另一个方法点,而无需virtual

3 个答案:

答案 0 :(得分:12)

使方法成为虚拟,以便您可以模拟它们。 (它们不需要是抽象的。)

如果你不能这样做,那么用另一个类包装类。使包装器的方法成为虚拟的,并且在默认实现中,只需将调用调用转发给原始类。只要程序使用原始类,请将其替换为包装器。现在,模拟包装器。

答案 1 :(得分:6)

  

要模拟我们需要继承的对象   它,但这是不可能的   情况下。

我建议你说“我需要模仿这个”的每个课程都应该基于一个界面。

换句话说,如果您有需要模拟的方法,则应将它们放入接口,然后要模拟的类实现该接口。然后,通过在模拟对象中实现相同的接口来创建模拟。

另一种方法是使用Mocking库。你可以看看这些问题:

What is your favorite Delphi mocking library?

这个框架也包括模拟对象:

http://code.google.com/p/emballo/

模拟对象还应该鼓励在代码中正确使用依赖注入。

答案 2 :(得分:5)

您不仅应该使方法成为虚拟,还应该声明纯虚基类,并使其他类仅使用纯虚基类名。现在你可以使用我们称之为“Liskov替换原则”的东西,你可以根据需要制作抽象基类的具体子类型。由于抽象基类的工作原理就像接口在delphi中工作一样,减去引用计数部分,因此您可以获得两全其美的效果。你可以真正保持你的应用程序代码简单,并以这种方式减少不良耦合,另外你可以获得自己组合在一起的单元可测试的“复合对象”。

// in UnitBase.pas
TMyClassBase = class
public
  procedure Method1; virtual; abstract;
  procedure Method2; virtual; abstract;
end; 

// in UnitReal.pas
TMyClassReal = class(TMyClassbase)
public
  procedure Method1; override;
  procedure Method2; override;
end; 

// in UnitMock.pas 
TMyClassMock = class(TMyClassbase)
public
  procedure Method1; override;
  procedure Method2; override;
end; 

在使用“TMyClass”的地方,将其更改为使用TMyClassbase:

TMyOtherClass = class(TMyOtherClassBase)
private
  FMyThing:TMyClassbase;
public
  property MyThing:TMyClassBase read FMyThing write FMyThing;
end;

通过在运行时连接TMyOtherclass,您可以决定是使用real还是mock类:

// in my realapp.pas
MyOtherClassObj :=   TMyotherClass.Create;
MyOtherClassObj.MyThing :=  TMyOtherClassReal.Create;  // real object

// in my unittest.pas
MyOtherClassObj :=   TMyotherClass.Create;
MyOtherClassObj.MyThing :=  TMyOtherClassMock.Create;  // mock object

(不要忘记稍后解开MyOtherClassObj.MyThing,否则你会有泄漏)